1*1a96fba6SXin Li // Copyright 2014 The Chromium OS Authors. All rights reserved.
2*1a96fba6SXin Li // Use of this source code is governed by a BSD-style license that can be
3*1a96fba6SXin Li // found in the LICENSE file.
4*1a96fba6SXin Li
5*1a96fba6SXin Li // Internal implementation of brillo::Any class.
6*1a96fba6SXin Li
7*1a96fba6SXin Li #ifndef LIBBRILLO_BRILLO_ANY_INTERNAL_IMPL_H_
8*1a96fba6SXin Li #define LIBBRILLO_BRILLO_ANY_INTERNAL_IMPL_H_
9*1a96fba6SXin Li
10*1a96fba6SXin Li #include <type_traits>
11*1a96fba6SXin Li #include <typeinfo>
12*1a96fba6SXin Li #include <utility>
13*1a96fba6SXin Li
14*1a96fba6SXin Li #include <base/logging.h>
15*1a96fba6SXin Li #include <brillo/dbus/data_serialization.h>
16*1a96fba6SXin Li #include <brillo/type_name_undecorate.h>
17*1a96fba6SXin Li
18*1a96fba6SXin Li namespace brillo {
19*1a96fba6SXin Li
20*1a96fba6SXin Li namespace internal_details {
21*1a96fba6SXin Li
22*1a96fba6SXin Li // An extension to std::is_convertible to allow conversion from an enum to
23*1a96fba6SXin Li // an integral type which std::is_convertible does not indicate as supported.
24*1a96fba6SXin Li template <typename From, typename To>
25*1a96fba6SXin Li struct IsConvertible
26*1a96fba6SXin Li : public std::integral_constant<
27*1a96fba6SXin Li bool,
28*1a96fba6SXin Li std::is_convertible<From, To>::value ||
29*1a96fba6SXin Li (std::is_enum<From>::value && std::is_integral<To>::value)> {};
30*1a96fba6SXin Li
31*1a96fba6SXin Li // TryConvert is a helper function that does a safe compile-time conditional
32*1a96fba6SXin Li // type cast between data types that may not be always convertible.
33*1a96fba6SXin Li // From and To are the source and destination types.
34*1a96fba6SXin Li // The function returns true if conversion was possible/successful.
35*1a96fba6SXin Li template <typename From, typename To>
36*1a96fba6SXin Li inline typename std::enable_if<IsConvertible<From, To>::value, bool>::type
TryConvert(const From & in,To * out)37*1a96fba6SXin Li TryConvert(const From& in, To* out) {
38*1a96fba6SXin Li *out = static_cast<To>(in);
39*1a96fba6SXin Li return true;
40*1a96fba6SXin Li }
41*1a96fba6SXin Li template <typename From, typename To>
42*1a96fba6SXin Li inline typename std::enable_if<!IsConvertible<From, To>::value, bool>::type
TryConvert(const From &,To *)43*1a96fba6SXin Li TryConvert(const From& /* in */, To* /* out */) {
44*1a96fba6SXin Li return false;
45*1a96fba6SXin Li }
46*1a96fba6SXin Li
47*1a96fba6SXin Li //////////////////////////////////////////////////////////////////////////////
48*1a96fba6SXin Li // Provide a way to compare values of unspecified types without compiler errors
49*1a96fba6SXin Li // when no operator==() is provided for a given type. This is important to
50*1a96fba6SXin Li // allow Any class to have operator==(), yet still allowing arbitrary types
51*1a96fba6SXin Li // (not necessarily comparable) to be placed inside Any without resulting in
52*1a96fba6SXin Li // compile-time error.
53*1a96fba6SXin Li //
54*1a96fba6SXin Li // We achieve this in two ways. First, we provide a IsEqualityComparable<T>
55*1a96fba6SXin Li // class that can be used in compile-time conditions to determine if there is
56*1a96fba6SXin Li // operator==() defined that takes values of type T (or which can be implicitly
57*1a96fba6SXin Li // converted to type T). Secondly, this allows us to specialize a helper
58*1a96fba6SXin Li // compare function EqCompare<T>(v1, v2) to use operator==() for types that
59*1a96fba6SXin Li // are comparable, and just return false for those that are not.
60*1a96fba6SXin Li //
61*1a96fba6SXin Li // IsEqualityComparableHelper<T> is a helper class for implementing an
62*1a96fba6SXin Li // an STL-compatible IsEqualityComparable<T> containing a Boolean member |value|
63*1a96fba6SXin Li // which evaluates to true for comparable types and false otherwise.
64*1a96fba6SXin Li template<typename T>
65*1a96fba6SXin Li struct IsEqualityComparableHelper {
66*1a96fba6SXin Li struct IntWrapper {
67*1a96fba6SXin Li // A special structure that provides a constructor that takes an int.
68*1a96fba6SXin Li // This way, an int argument passed to a function will be favored over
69*1a96fba6SXin Li // IntWrapper when both overloads are provided.
70*1a96fba6SXin Li // Also this constructor must NOT be explicit.
71*1a96fba6SXin Li // NOLINTNEXTLINE(runtime/explicit)
72*1a96fba6SXin Li // NOLINT: Allow implicit conversion from int.
IntWrapperIsEqualityComparableHelper::IntWrapper73*1a96fba6SXin Li IntWrapper(int /* dummy */) {} // do nothing, NOLINT
74*1a96fba6SXin Li };
75*1a96fba6SXin Li
76*1a96fba6SXin Li // Here is an obscure trick to determine if a type U has operator==().
77*1a96fba6SXin Li // We are providing two function prototypes for TriggerFunction. One that
78*1a96fba6SXin Li // takes an argument of type IntWrapper (which is implicitly convertible from
79*1a96fba6SXin Li // an int), and returns an std::false_type. This is a fall-back mechanism.
80*1a96fba6SXin Li template<typename U>
81*1a96fba6SXin Li static std::false_type TriggerFunction(IntWrapper dummy);
82*1a96fba6SXin Li
83*1a96fba6SXin Li // The second overload of TriggerFunction takes an int (explicitly) and
84*1a96fba6SXin Li // returns std::true_type. If both overloads are available, this one will be
85*1a96fba6SXin Li // chosen when referencing it as TriggerFunction(0), since it is a better
86*1a96fba6SXin Li // (more specific) match.
87*1a96fba6SXin Li //
88*1a96fba6SXin Li // However this overload is available only for types that support operator==.
89*1a96fba6SXin Li // This is achieved by employing SFINAE mechanism inside a template function
90*1a96fba6SXin Li // overload that refers to operator==() for two values of types U&. This is
91*1a96fba6SXin Li // used inside decltype(), so no actual code is executed. If the types
92*1a96fba6SXin Li // are not comparable, reference to "==" would fail and the compiler will
93*1a96fba6SXin Li // simply ignore this overload due to SFIANE.
94*1a96fba6SXin Li //
95*1a96fba6SXin Li // The final little trick used here is the reliance on operator comma inside
96*1a96fba6SXin Li // the decltype() expression. The result of the expression is always
97*1a96fba6SXin Li // std::true_type(). The expression on the left of comma is just evaluated and
98*1a96fba6SXin Li // discarded. If it evaluates successfully (i.e. the type has operator==), the
99*1a96fba6SXin Li // return value of the function is set to be std::true_value. If it fails,
100*1a96fba6SXin Li // the whole function prototype is discarded and is not available in the
101*1a96fba6SXin Li // IsEqualityComparableHelper<T> class.
102*1a96fba6SXin Li //
103*1a96fba6SXin Li // Here we use std::declval<U&>() to make sure we have operator==() that takes
104*1a96fba6SXin Li // lvalue references to type U which is not necessarily default-constructible.
105*1a96fba6SXin Li template<typename U>
106*1a96fba6SXin Li static decltype((std::declval<U&>() == std::declval<U&>()), std::true_type())
107*1a96fba6SXin Li TriggerFunction(int dummy);
108*1a96fba6SXin Li
109*1a96fba6SXin Li // Finally, use the return type of the overload of TriggerFunction that
110*1a96fba6SXin Li // matches the argument (int) to be aliased to type |type|. If T is
111*1a96fba6SXin Li // comparable, there will be two overloads and the more specific (int) will
112*1a96fba6SXin Li // be chosen which returns std::true_value. If the type is non-comparable,
113*1a96fba6SXin Li // there will be only one version of TriggerFunction available which
114*1a96fba6SXin Li // returns std::false_value.
115*1a96fba6SXin Li using type = decltype(TriggerFunction<T>(0));
116*1a96fba6SXin Li };
117*1a96fba6SXin Li
118*1a96fba6SXin Li // IsEqualityComparable<T> is simply a class that derives from either
119*1a96fba6SXin Li // std::true_value, if type T is comparable, or from std::false_value, if the
120*1a96fba6SXin Li // type is non-comparable. We just use |type| alias from
121*1a96fba6SXin Li // IsEqualityComparableHelper<T> as the base class.
122*1a96fba6SXin Li template<typename T>
123*1a96fba6SXin Li struct IsEqualityComparable : IsEqualityComparableHelper<T>::type {};
124*1a96fba6SXin Li
125*1a96fba6SXin Li // EqCompare() overload for non-comparable types. Always returns false.
126*1a96fba6SXin Li template<typename T>
127*1a96fba6SXin Li inline typename std::enable_if<!IsEqualityComparable<T>::value, bool>::type
EqCompare(const T &,const T &)128*1a96fba6SXin Li EqCompare(const T& /* v1 */, const T& /* v2 */) {
129*1a96fba6SXin Li return false;
130*1a96fba6SXin Li }
131*1a96fba6SXin Li
132*1a96fba6SXin Li // EqCompare overload for comparable types. Calls operator==(v1, v2) to compare.
133*1a96fba6SXin Li template<typename T>
134*1a96fba6SXin Li inline typename std::enable_if<IsEqualityComparable<T>::value, bool>::type
EqCompare(const T & v1,const T & v2)135*1a96fba6SXin Li EqCompare(const T& v1, const T& v2) {
136*1a96fba6SXin Li return (v1 == v2);
137*1a96fba6SXin Li }
138*1a96fba6SXin Li
139*1a96fba6SXin Li //////////////////////////////////////////////////////////////////////////////
140*1a96fba6SXin Li
141*1a96fba6SXin Li class Buffer; // Forward declaration of data buffer container.
142*1a96fba6SXin Li
143*1a96fba6SXin Li // Abstract base class for contained variant data.
144*1a96fba6SXin Li struct Data {
~DataData145*1a96fba6SXin Li virtual ~Data() {}
146*1a96fba6SXin Li // Returns the type tag (name) for the contained data.
147*1a96fba6SXin Li virtual const char* GetTypeTag() const = 0;
148*1a96fba6SXin Li // Copies the contained data to the output |buffer|.
149*1a96fba6SXin Li virtual void CopyTo(Buffer* buffer) const = 0;
150*1a96fba6SXin Li // Moves the contained data to the output |buffer|.
151*1a96fba6SXin Li virtual void MoveTo(Buffer* buffer) = 0;
152*1a96fba6SXin Li // Checks if the contained data is an integer type (not necessarily an 'int').
153*1a96fba6SXin Li virtual bool IsConvertibleToInteger() const = 0;
154*1a96fba6SXin Li // Gets the contained integral value as an integer.
155*1a96fba6SXin Li virtual intmax_t GetAsInteger() const = 0;
156*1a96fba6SXin Li // Writes the contained value to the D-Bus message buffer.
157*1a96fba6SXin Li virtual void AppendToDBusMessage(::dbus::MessageWriter* writer) const = 0;
158*1a96fba6SXin Li // Compares if the two data containers have objects of the same value.
159*1a96fba6SXin Li virtual bool CompareEqual(const Data* other_data) const = 0;
160*1a96fba6SXin Li };
161*1a96fba6SXin Li
162*1a96fba6SXin Li // Concrete implementation of variant data of type T.
163*1a96fba6SXin Li template<typename T>
164*1a96fba6SXin Li struct TypedData : public Data {
TypedDataTypedData165*1a96fba6SXin Li explicit TypedData(const T& value) : value_(value) {}
166*1a96fba6SXin Li // NOLINTNEXTLINE(build/c++11)
TypedDataTypedData167*1a96fba6SXin Li explicit TypedData(T&& value) : value_(std::move(value)) {}
168*1a96fba6SXin Li
GetTypeTagTypedData169*1a96fba6SXin Li const char* GetTypeTag() const override { return brillo::GetTypeTag<T>(); }
170*1a96fba6SXin Li void CopyTo(Buffer* buffer) const override;
171*1a96fba6SXin Li void MoveTo(Buffer* buffer) override;
IsConvertibleToIntegerTypedData172*1a96fba6SXin Li bool IsConvertibleToInteger() const override {
173*1a96fba6SXin Li return std::is_integral<T>::value || std::is_enum<T>::value;
174*1a96fba6SXin Li }
GetAsIntegerTypedData175*1a96fba6SXin Li intmax_t GetAsInteger() const override {
176*1a96fba6SXin Li intmax_t int_val = 0;
177*1a96fba6SXin Li bool converted = TryConvert(value_, &int_val);
178*1a96fba6SXin Li CHECK(converted) << "Unable to convert value of type '"
179*1a96fba6SXin Li << GetUndecoratedTypeName<T>() << "' to integer";
180*1a96fba6SXin Li return int_val;
181*1a96fba6SXin Li }
182*1a96fba6SXin Li
183*1a96fba6SXin Li template <typename U>
184*1a96fba6SXin Li static typename std::enable_if<dbus_utils::IsTypeSupported<U>::value>::type
AppendValueHelperTypedData185*1a96fba6SXin Li AppendValueHelper(::dbus::MessageWriter* writer, const U& value) {
186*1a96fba6SXin Li brillo::dbus_utils::AppendValueToWriterAsVariant(writer, value);
187*1a96fba6SXin Li }
188*1a96fba6SXin Li template <typename U>
189*1a96fba6SXin Li static typename std::enable_if<!dbus_utils::IsTypeSupported<U>::value>::type
AppendValueHelperTypedData190*1a96fba6SXin Li AppendValueHelper(::dbus::MessageWriter* /* writer */, const U& /* value */) {
191*1a96fba6SXin Li LOG(FATAL) << "Type '" << GetUndecoratedTypeName<U>()
192*1a96fba6SXin Li << "' is not supported by D-Bus";
193*1a96fba6SXin Li }
194*1a96fba6SXin Li
AppendToDBusMessageTypedData195*1a96fba6SXin Li void AppendToDBusMessage(::dbus::MessageWriter* writer) const override {
196*1a96fba6SXin Li return AppendValueHelper(writer, value_);
197*1a96fba6SXin Li }
198*1a96fba6SXin Li
CompareEqualTypedData199*1a96fba6SXin Li bool CompareEqual(const Data* other_data) const override {
200*1a96fba6SXin Li return EqCompare<T>(value_,
201*1a96fba6SXin Li static_cast<const TypedData<T>*>(other_data)->value_);
202*1a96fba6SXin Li }
203*1a96fba6SXin Li
204*1a96fba6SXin Li // Special methods to copy/move data of the same type
205*1a96fba6SXin Li // without reallocating the buffer.
FastAssignTypedData206*1a96fba6SXin Li void FastAssign(const T& source) { value_ = source; }
207*1a96fba6SXin Li // NOLINTNEXTLINE(build/c++11)
FastAssignTypedData208*1a96fba6SXin Li void FastAssign(T&& source) { value_ = std::move(source); }
209*1a96fba6SXin Li
210*1a96fba6SXin Li T value_;
211*1a96fba6SXin Li };
212*1a96fba6SXin Li
213*1a96fba6SXin Li // Buffer class that stores the contained variant data.
214*1a96fba6SXin Li // To improve performance and reduce memory fragmentation, small variants
215*1a96fba6SXin Li // are stored in pre-allocated memory buffers that are part of the Any class.
216*1a96fba6SXin Li // If the memory requirements are larger than the set limit or the type is
217*1a96fba6SXin Li // non-trivially copyable, then the contained class is allocated in a separate
218*1a96fba6SXin Li // memory block and the pointer to that memory is contained within this memory
219*1a96fba6SXin Li // buffer class.
220*1a96fba6SXin Li class Buffer final {
221*1a96fba6SXin Li public:
222*1a96fba6SXin Li enum StorageType { kExternal, kContained };
Buffer()223*1a96fba6SXin Li Buffer() : external_ptr_(nullptr), storage_(kExternal) {}
~Buffer()224*1a96fba6SXin Li ~Buffer() { Clear(); }
225*1a96fba6SXin Li
Buffer(const Buffer & rhs)226*1a96fba6SXin Li Buffer(const Buffer& rhs) : Buffer() { rhs.CopyTo(this); }
227*1a96fba6SXin Li // NOLINTNEXTLINE(build/c++11)
Buffer(Buffer && rhs)228*1a96fba6SXin Li Buffer(Buffer&& rhs) : Buffer() { rhs.MoveTo(this); }
229*1a96fba6SXin Li Buffer& operator=(const Buffer& rhs) {
230*1a96fba6SXin Li rhs.CopyTo(this);
231*1a96fba6SXin Li return *this;
232*1a96fba6SXin Li }
233*1a96fba6SXin Li // NOLINTNEXTLINE(build/c++11)
234*1a96fba6SXin Li Buffer& operator=(Buffer&& rhs) {
235*1a96fba6SXin Li rhs.MoveTo(this);
236*1a96fba6SXin Li return *this;
237*1a96fba6SXin Li }
238*1a96fba6SXin Li
239*1a96fba6SXin Li // Returns the underlying pointer to contained data. Uses either the pointer
240*1a96fba6SXin Li // or the raw data depending on |storage_| type.
GetDataPtr()241*1a96fba6SXin Li inline Data* GetDataPtr() {
242*1a96fba6SXin Li return (storage_ == kExternal) ? external_ptr_
243*1a96fba6SXin Li : reinterpret_cast<Data*>(contained_buffer_);
244*1a96fba6SXin Li }
GetDataPtr()245*1a96fba6SXin Li inline const Data* GetDataPtr() const {
246*1a96fba6SXin Li return (storage_ == kExternal)
247*1a96fba6SXin Li ? external_ptr_
248*1a96fba6SXin Li : reinterpret_cast<const Data*>(contained_buffer_);
249*1a96fba6SXin Li }
250*1a96fba6SXin Li
251*1a96fba6SXin Li // Destroys the contained object (and frees memory if needed).
Clear()252*1a96fba6SXin Li void Clear() {
253*1a96fba6SXin Li Data* data = GetDataPtr();
254*1a96fba6SXin Li if (storage_ == kExternal) {
255*1a96fba6SXin Li delete data;
256*1a96fba6SXin Li } else {
257*1a96fba6SXin Li // Call the destructor manually, since the object was constructed inline
258*1a96fba6SXin Li // in the pre-allocated buffer. We still need to call the destructor
259*1a96fba6SXin Li // to free any associated resources, but we can't call delete |data| here.
260*1a96fba6SXin Li data->~Data();
261*1a96fba6SXin Li }
262*1a96fba6SXin Li external_ptr_ = nullptr;
263*1a96fba6SXin Li storage_ = kExternal;
264*1a96fba6SXin Li }
265*1a96fba6SXin Li
266*1a96fba6SXin Li // Stores a value of type T.
267*1a96fba6SXin Li template<typename T>
Assign(T && value)268*1a96fba6SXin Li void Assign(T&& value) { // NOLINT(build/c++11)
269*1a96fba6SXin Li using Type = typename std::decay<T>::type;
270*1a96fba6SXin Li using DataType = TypedData<Type>;
271*1a96fba6SXin Li Data* ptr = GetDataPtr();
272*1a96fba6SXin Li if (ptr && strcmp(ptr->GetTypeTag(), GetTypeTag<Type>()) == 0) {
273*1a96fba6SXin Li // We assign the data to the variant container, which already
274*1a96fba6SXin Li // has the data of the same type. Do fast copy/move with no memory
275*1a96fba6SXin Li // reallocation.
276*1a96fba6SXin Li DataType* typed_ptr = static_cast<DataType*>(ptr);
277*1a96fba6SXin Li // NOLINTNEXTLINE(build/c++11)
278*1a96fba6SXin Li typed_ptr->FastAssign(std::forward<T>(value));
279*1a96fba6SXin Li } else {
280*1a96fba6SXin Li Clear();
281*1a96fba6SXin Li // TODO(avakulenko): [see crbug.com/379833]
282*1a96fba6SXin Li // Unfortunately, GCC doesn't support std::is_trivially_copyable<T> yet,
283*1a96fba6SXin Li // so using std::is_trivial instead, which is a bit more restrictive.
284*1a96fba6SXin Li // Once GCC has support for is_trivially_copyable, update the following.
285*1a96fba6SXin Li if (!std::is_trivial<Type>::value ||
286*1a96fba6SXin Li sizeof(DataType) > sizeof(contained_buffer_)) {
287*1a96fba6SXin Li // If it is too big or not trivially copyable, allocate it separately.
288*1a96fba6SXin Li // NOLINTNEXTLINE(build/c++11)
289*1a96fba6SXin Li external_ptr_ = new DataType(std::forward<T>(value));
290*1a96fba6SXin Li storage_ = kExternal;
291*1a96fba6SXin Li } else {
292*1a96fba6SXin Li // Otherwise just use the pre-allocated buffer.
293*1a96fba6SXin Li DataType* address = reinterpret_cast<DataType*>(contained_buffer_);
294*1a96fba6SXin Li // Make sure we still call the copy/move constructor.
295*1a96fba6SXin Li // Call the constructor manually by using placement 'new'.
296*1a96fba6SXin Li // NOLINTNEXTLINE(build/c++11)
297*1a96fba6SXin Li new (address) DataType(std::forward<T>(value));
298*1a96fba6SXin Li storage_ = kContained;
299*1a96fba6SXin Li }
300*1a96fba6SXin Li }
301*1a96fba6SXin Li }
302*1a96fba6SXin Li
303*1a96fba6SXin Li // Helper methods to retrieve a reference to contained data.
304*1a96fba6SXin Li // These assume that type checking has already been performed by Any
305*1a96fba6SXin Li // so the type cast is valid and will succeed.
306*1a96fba6SXin Li template<typename T>
GetData()307*1a96fba6SXin Li const T& GetData() const {
308*1a96fba6SXin Li using DataType = internal_details::TypedData<typename std::decay<T>::type>;
309*1a96fba6SXin Li return static_cast<const DataType*>(GetDataPtr())->value_;
310*1a96fba6SXin Li }
311*1a96fba6SXin Li template<typename T>
GetData()312*1a96fba6SXin Li T& GetData() {
313*1a96fba6SXin Li using DataType = internal_details::TypedData<typename std::decay<T>::type>;
314*1a96fba6SXin Li return static_cast<DataType*>(GetDataPtr())->value_;
315*1a96fba6SXin Li }
316*1a96fba6SXin Li
317*1a96fba6SXin Li // Returns true if the buffer has no contained data.
IsEmpty()318*1a96fba6SXin Li bool IsEmpty() const {
319*1a96fba6SXin Li return (storage_ == kExternal && external_ptr_ == nullptr);
320*1a96fba6SXin Li }
321*1a96fba6SXin Li
322*1a96fba6SXin Li // Copies the data from the current buffer into the |destination|.
CopyTo(Buffer * destination)323*1a96fba6SXin Li void CopyTo(Buffer* destination) const {
324*1a96fba6SXin Li if (IsEmpty()) {
325*1a96fba6SXin Li destination->Clear();
326*1a96fba6SXin Li } else {
327*1a96fba6SXin Li GetDataPtr()->CopyTo(destination);
328*1a96fba6SXin Li }
329*1a96fba6SXin Li }
330*1a96fba6SXin Li
331*1a96fba6SXin Li // Moves the data from the current buffer into the |destination|.
MoveTo(Buffer * destination)332*1a96fba6SXin Li void MoveTo(Buffer* destination) {
333*1a96fba6SXin Li if (IsEmpty()) {
334*1a96fba6SXin Li destination->Clear();
335*1a96fba6SXin Li } else {
336*1a96fba6SXin Li if (storage_ == kExternal) {
337*1a96fba6SXin Li destination->Clear();
338*1a96fba6SXin Li destination->storage_ = kExternal;
339*1a96fba6SXin Li destination->external_ptr_ = external_ptr_;
340*1a96fba6SXin Li external_ptr_ = nullptr;
341*1a96fba6SXin Li } else {
342*1a96fba6SXin Li GetDataPtr()->MoveTo(destination);
343*1a96fba6SXin Li }
344*1a96fba6SXin Li }
345*1a96fba6SXin Li }
346*1a96fba6SXin Li
347*1a96fba6SXin Li union {
348*1a96fba6SXin Li // |external_ptr_| is a pointer to a larger object allocated in
349*1a96fba6SXin Li // a separate memory block.
350*1a96fba6SXin Li Data* external_ptr_;
351*1a96fba6SXin Li // |contained_buffer_| is a pre-allocated buffer for smaller/simple objects.
352*1a96fba6SXin Li // Pre-allocate enough memory to store objects as big as "double".
353*1a96fba6SXin Li unsigned char contained_buffer_[sizeof(TypedData<double>)];
354*1a96fba6SXin Li };
355*1a96fba6SXin Li // Depending on a value of |storage_|, either |external_ptr_| or
356*1a96fba6SXin Li // |contained_buffer_| above is used to get a pointer to memory containing
357*1a96fba6SXin Li // the variant data.
358*1a96fba6SXin Li StorageType storage_; // Declare after the union to eliminate member padding.
359*1a96fba6SXin Li };
360*1a96fba6SXin Li
361*1a96fba6SXin Li template <typename T>
CopyTo(Buffer * buffer)362*1a96fba6SXin Li void TypedData<T>::CopyTo(Buffer* buffer) const {
363*1a96fba6SXin Li buffer->Assign(value_);
364*1a96fba6SXin Li }
365*1a96fba6SXin Li template <typename T>
MoveTo(Buffer * buffer)366*1a96fba6SXin Li void TypedData<T>::MoveTo(Buffer* buffer) {
367*1a96fba6SXin Li buffer->Assign(std::move(value_));
368*1a96fba6SXin Li }
369*1a96fba6SXin Li
370*1a96fba6SXin Li } // namespace internal_details
371*1a96fba6SXin Li
372*1a96fba6SXin Li } // namespace brillo
373*1a96fba6SXin Li
374*1a96fba6SXin Li #endif // LIBBRILLO_BRILLO_ANY_INTERNAL_IMPL_H_
375