xref: /aosp_15_r20/external/libbrillo/brillo/any_internal_impl.h (revision 1a96fba65179ea7d3f56207137718607415c5953)
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