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 // This is an implementation of a "true" variant class in C++.
6*1a96fba6SXin Li // The brillo::Any class can hold any C++ type, but both the setter and
7*1a96fba6SXin Li // getter sites need to know the actual type of data.
8*1a96fba6SXin Li // Note that C-style arrays when stored in Any are reduced to simple
9*1a96fba6SXin Li // data pointers. Any will not copy a contents of the array.
10*1a96fba6SXin Li // const int data[] = [1,2,3];
11*1a96fba6SXin Li // Any v(data); // stores const int*, effectively "Any v(&data[0]);"
12*1a96fba6SXin Li
13*1a96fba6SXin Li // brillo::Any is a value type. Which means, the data is copied into it
14*1a96fba6SXin Li // and Any owns it. The owned object (stored by value) will be destroyed
15*1a96fba6SXin Li // when Any is cleared or reassigned. The contained value type must be
16*1a96fba6SXin Li // copy-constructible. You can also store pointers and references to objects.
17*1a96fba6SXin Li // Storing pointers is trivial. In order to store a reference, you can
18*1a96fba6SXin Li // use helper functions std::ref() and std::cref() to create non-const and
19*1a96fba6SXin Li // const references respectively. In such a case, the type of contained data
20*1a96fba6SXin Li // will be std::reference_wrapper<T>. See 'References' unit tests in
21*1a96fba6SXin Li // any_test.cc for examples.
22*1a96fba6SXin Li
23*1a96fba6SXin Li #ifndef LIBBRILLO_BRILLO_ANY_H_
24*1a96fba6SXin Li #define LIBBRILLO_BRILLO_ANY_H_
25*1a96fba6SXin Li
26*1a96fba6SXin Li #include <brillo/any_internal_impl.h>
27*1a96fba6SXin Li
28*1a96fba6SXin Li #include <algorithm>
29*1a96fba6SXin Li #include <string>
30*1a96fba6SXin Li #include <utility>
31*1a96fba6SXin Li
32*1a96fba6SXin Li #include <brillo/brillo_export.h>
33*1a96fba6SXin Li #include <brillo/type_name_undecorate.h>
34*1a96fba6SXin Li
35*1a96fba6SXin Li namespace dbus {
36*1a96fba6SXin Li class MessageWriter;
37*1a96fba6SXin Li } // namespace dbus
38*1a96fba6SXin Li
39*1a96fba6SXin Li namespace brillo {
40*1a96fba6SXin Li
41*1a96fba6SXin Li class BRILLO_EXPORT Any final {
42*1a96fba6SXin Li public:
43*1a96fba6SXin Li Any(); // Do not inline to hide internal_details::Buffer from export table.
44*1a96fba6SXin Li // Standard copy/move constructors. This is a value-class container
45*1a96fba6SXin Li // that must be copy-constructible and movable. The copy constructors
46*1a96fba6SXin Li // should not be marked as explicit.
47*1a96fba6SXin Li Any(const Any& rhs);
48*1a96fba6SXin Li Any(Any&& rhs); // NOLINT(build/c++11)
49*1a96fba6SXin Li // Typed constructor that stores a value of type T in the Any.
50*1a96fba6SXin Li template<class T>
Any(T value)51*1a96fba6SXin Li inline Any(T value) { // NOLINT(runtime/explicit)
52*1a96fba6SXin Li data_buffer_.Assign(std::move(value));
53*1a96fba6SXin Li }
54*1a96fba6SXin Li
55*1a96fba6SXin Li // Not declaring the destructor as virtual since this is a sealed class
56*1a96fba6SXin Li // and there is no need to introduce a virtual table to it.
57*1a96fba6SXin Li ~Any();
58*1a96fba6SXin Li
59*1a96fba6SXin Li // Assignment operators.
60*1a96fba6SXin Li Any& operator=(const Any& rhs);
61*1a96fba6SXin Li Any& operator=(Any&& rhs); // NOLINT(build/c++11)
62*1a96fba6SXin Li template<class T>
63*1a96fba6SXin Li inline Any& operator=(T value) {
64*1a96fba6SXin Li data_buffer_.Assign(std::move(value));
65*1a96fba6SXin Li return *this;
66*1a96fba6SXin Li }
67*1a96fba6SXin Li
68*1a96fba6SXin Li // Compares the contents of two Any objects for equality. Note that the
69*1a96fba6SXin Li // contained type must be equality-comparable (must have operator== defined).
70*1a96fba6SXin Li // If operator==() is not available for contained type, comparison operation
71*1a96fba6SXin Li // always returns false (as if the data were different).
72*1a96fba6SXin Li bool operator==(const Any& rhs) const;
73*1a96fba6SXin Li inline bool operator!=(const Any& rhs) const { return !operator==(rhs); }
74*1a96fba6SXin Li
75*1a96fba6SXin Li // Checks if the given type DestType can be obtained from the Any.
76*1a96fba6SXin Li // For example, to check if Any has a 'double' value in it:
77*1a96fba6SXin Li // any.IsTypeCompatible<double>()
78*1a96fba6SXin Li template<typename DestType>
IsTypeCompatible()79*1a96fba6SXin Li bool IsTypeCompatible() const {
80*1a96fba6SXin Li // Make sure the requested type DestType conforms to the storage
81*1a96fba6SXin Li // requirements of Any. We always store the data by value, which means we
82*1a96fba6SXin Li // strip away any references as well as cv-qualifiers. So, if the user
83*1a96fba6SXin Li // stores "const int&", we actually store just an "int".
84*1a96fba6SXin Li // When calling IsTypeCompatible, we need to do a similar "type cleansing"
85*1a96fba6SXin Li // to make sure the requested type matches the type of data actually stored,
86*1a96fba6SXin Li // so this "canonical" type is used for type checking below.
87*1a96fba6SXin Li using CanonicalDestType = typename std::decay<DestType>::type;
88*1a96fba6SXin Li const char* contained_type = GetTypeTagInternal();
89*1a96fba6SXin Li if (strcmp(GetTypeTag<CanonicalDestType>(), contained_type) == 0)
90*1a96fba6SXin Li return true;
91*1a96fba6SXin Li
92*1a96fba6SXin Li if (!std::is_pointer<CanonicalDestType>::value)
93*1a96fba6SXin Li return false;
94*1a96fba6SXin Li
95*1a96fba6SXin Li // If asking for a const pointer from a variant containing non-const
96*1a96fba6SXin Li // pointer, still satisfy the request. So, we need to remove the pointer
97*1a96fba6SXin Li // specification first, then strip the const/volatile qualifiers, then
98*1a96fba6SXin Li // re-add the pointer back, so "const int*" would become "int*".
99*1a96fba6SXin Li using NonPointer = typename std::remove_pointer<CanonicalDestType>::type;
100*1a96fba6SXin Li using CanonicalDestTypeNoConst = typename std::add_pointer<
101*1a96fba6SXin Li typename std::remove_const<NonPointer>::type>::type;
102*1a96fba6SXin Li if (strcmp(GetTypeTag<CanonicalDestTypeNoConst>(), contained_type) == 0)
103*1a96fba6SXin Li return true;
104*1a96fba6SXin Li
105*1a96fba6SXin Li using CanonicalDestTypeNoVolatile = typename std::add_pointer<
106*1a96fba6SXin Li typename std::remove_volatile<NonPointer>::type>::type;
107*1a96fba6SXin Li if (strcmp(GetTypeTag<CanonicalDestTypeNoVolatile>(), contained_type) == 0)
108*1a96fba6SXin Li return true;
109*1a96fba6SXin Li
110*1a96fba6SXin Li using CanonicalDestTypeNoConstOrVolatile = typename std::add_pointer<
111*1a96fba6SXin Li typename std::remove_cv<NonPointer>::type>::type;
112*1a96fba6SXin Li return strcmp(GetTypeTag<CanonicalDestTypeNoConstOrVolatile>(),
113*1a96fba6SXin Li contained_type) == 0;
114*1a96fba6SXin Li }
115*1a96fba6SXin Li
116*1a96fba6SXin Li // Returns immutable data contained in Any.
117*1a96fba6SXin Li // Aborts if Any doesn't contain a value of type T, or trivially
118*1a96fba6SXin Li // convertible to/compatible with it.
119*1a96fba6SXin Li template<typename T>
Get()120*1a96fba6SXin Li const T& Get() const {
121*1a96fba6SXin Li CHECK(IsTypeCompatible<T>())
122*1a96fba6SXin Li << "Requesting value of type '" << brillo::GetUndecoratedTypeName<T>()
123*1a96fba6SXin Li << "' from variant containing '" << GetUndecoratedTypeName()
124*1a96fba6SXin Li << "'";
125*1a96fba6SXin Li return data_buffer_.GetData<T>();
126*1a96fba6SXin Li }
127*1a96fba6SXin Li
128*1a96fba6SXin Li // Returns a copy of data in Any and returns true when that data is
129*1a96fba6SXin Li // compatible with T. Returns false if contained data is incompatible.
130*1a96fba6SXin Li template<typename T>
GetValue(T * value)131*1a96fba6SXin Li bool GetValue(T* value) const {
132*1a96fba6SXin Li if (!IsTypeCompatible<T>()) {
133*1a96fba6SXin Li return false;
134*1a96fba6SXin Li }
135*1a96fba6SXin Li *value = Get<T>();
136*1a96fba6SXin Li return true;
137*1a96fba6SXin Li }
138*1a96fba6SXin Li
139*1a96fba6SXin Li // Returns a pointer to mutable value of type T contained within Any.
140*1a96fba6SXin Li // No data copying is made, the data pointed to is still owned by Any.
141*1a96fba6SXin Li // If Any doesn't contain a value of type T, or trivially
142*1a96fba6SXin Li // convertible/compatible to/with it, then it returns nullptr.
143*1a96fba6SXin Li template<typename T>
GetPtr()144*1a96fba6SXin Li T* GetPtr() {
145*1a96fba6SXin Li if (!IsTypeCompatible<T>())
146*1a96fba6SXin Li return nullptr;
147*1a96fba6SXin Li return &(data_buffer_.GetData<T>());
148*1a96fba6SXin Li }
149*1a96fba6SXin Li
150*1a96fba6SXin Li // Returns a copy of the data contained in Any.
151*1a96fba6SXin Li // If the Any doesn't contain a compatible value, the provided default
152*1a96fba6SXin Li // |def_val| is returned instead.
153*1a96fba6SXin Li template<typename T>
TryGet(typename std::decay<T>::type const & def_val)154*1a96fba6SXin Li T TryGet(typename std::decay<T>::type const& def_val) const {
155*1a96fba6SXin Li if (!IsTypeCompatible<T>())
156*1a96fba6SXin Li return def_val;
157*1a96fba6SXin Li return data_buffer_.GetData<T>();
158*1a96fba6SXin Li }
159*1a96fba6SXin Li
160*1a96fba6SXin Li // A convenience specialization of the above function where the default
161*1a96fba6SXin Li // value of type T is returned in case the underlying Get() fails.
162*1a96fba6SXin Li template<typename T>
TryGet()163*1a96fba6SXin Li T TryGet() const {
164*1a96fba6SXin Li return TryGet<T>(typename std::decay<T>::type());
165*1a96fba6SXin Li }
166*1a96fba6SXin Li
167*1a96fba6SXin Li // Returns the undecorated name of the type contained within Any.
GetUndecoratedTypeName()168*1a96fba6SXin Li inline std::string GetUndecoratedTypeName() const {
169*1a96fba6SXin Li return GetUndecoratedTypeNameForTag(GetTypeTagInternal());
170*1a96fba6SXin Li }
171*1a96fba6SXin Li // Swaps the value of this object with that of |other|.
172*1a96fba6SXin Li void Swap(Any& other);
173*1a96fba6SXin Li // Checks if Any is empty, that is, not containing a value of any type.
174*1a96fba6SXin Li bool IsEmpty() const;
175*1a96fba6SXin Li // Clears the Any and destroys any contained object. Makes it empty.
176*1a96fba6SXin Li void Clear();
177*1a96fba6SXin Li // Checks if Any contains a type convertible to integer.
178*1a96fba6SXin Li // Any type that match std::is_integral<T> and std::is_enum<T> is accepted.
179*1a96fba6SXin Li // That includes signed and unsigned char, short, int, long, etc as well as
180*1a96fba6SXin Li // 'bool' and enumerated types.
181*1a96fba6SXin Li // For 'integer' type, you can call GetAsInteger to do implicit type
182*1a96fba6SXin Li // conversion to intmax_t.
183*1a96fba6SXin Li bool IsConvertibleToInteger() const;
184*1a96fba6SXin Li // For integral types and enums contained in the Any, get the integer value
185*1a96fba6SXin Li // of data. This is a useful function to obtain an integer value when
186*1a96fba6SXin Li // any can possibly have unspecified integer, such as 'short', 'unsigned long'
187*1a96fba6SXin Li // and so on.
188*1a96fba6SXin Li intmax_t GetAsInteger() const;
189*1a96fba6SXin Li // Writes the contained data to D-Bus message writer, if the appropriate
190*1a96fba6SXin Li // serialization method for contained data of the given type is provided
191*1a96fba6SXin Li // (an appropriate specialization of AppendValueToWriter<T>() is available).
192*1a96fba6SXin Li // Returns false if the Any is empty or if there is no serialization method
193*1a96fba6SXin Li // defined for the contained data.
194*1a96fba6SXin Li void AppendToDBusMessageWriter(::dbus::MessageWriter* writer) const;
195*1a96fba6SXin Li
196*1a96fba6SXin Li private:
197*1a96fba6SXin Li // Returns a pointer to a static buffer containing type tag (sort of a type
198*1a96fba6SXin Li // name) of the contained value.
199*1a96fba6SXin Li const char* GetTypeTagInternal() const;
200*1a96fba6SXin Li
201*1a96fba6SXin Li // The data buffer for contained object.
202*1a96fba6SXin Li internal_details::Buffer data_buffer_;
203*1a96fba6SXin Li };
204*1a96fba6SXin Li
205*1a96fba6SXin Li } // namespace brillo
206*1a96fba6SXin Li
207*1a96fba6SXin Li namespace std {
208*1a96fba6SXin Li
209*1a96fba6SXin Li // Specialize std::swap() algorithm for brillo::Any class.
swap(brillo::Any & lhs,brillo::Any & rhs)210*1a96fba6SXin Li inline void swap(brillo::Any& lhs, brillo::Any& rhs) {
211*1a96fba6SXin Li lhs.Swap(rhs);
212*1a96fba6SXin Li }
213*1a96fba6SXin Li
214*1a96fba6SXin Li } // namespace std
215*1a96fba6SXin Li
216*1a96fba6SXin Li #endif // LIBBRILLO_BRILLO_ANY_H_
217