buffet: add C++ variant type (Any).

Any is the class that adds support for native variant types.

Any can store any C++ type which is copyable. Moveable-only
types (such as std::unique_ptr) cannot be stored directly,
however you can store pointers (or references) to such types.

Any stores small data embedded into the class itself without
having to allocate a separate storage for it. Larger data
(roughly, larger than 8 bytes) or non trivially-copyable types
are stored in a separate memory block and the pointer to that
block is stored in the Any class itself.

Any supports move semantics. You can move the stored value
from one Any into another without copying it.

At this point, there is no support for comparing the Any class
(equal or less than), so you cannot use it as a key in a map,
however you still can store it as a value.

The code that extracts the data from Any must know the exact
type stored. Calling Any::Get<T>() for incompatible type is
not supported. However you can use Any::TryGet<T>() instead
and provide a default value, which will be returned if Any
does not contain the expected data.

You can also inspect the type of the contained data by
using Any::GetType() and Any::IsTypeCompatible<T>() methods.

BUG=chromium:366709
TEST=All existing and new unit tests pass.

Change-Id: Ic47529935ddd39c792dff1db8667c76db91b16d4
Reviewed-on: https://chromium-review.googlesource.com/198590
Reviewed-by: Alex Vakulenko <avakulenko@chromium.org>
Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
Tested-by: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/buffet/any.h b/buffet/any.h
new file mode 100644
index 0000000..5ab249c
--- /dev/null
+++ b/buffet/any.h
@@ -0,0 +1,174 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is an implementation of a "true" variant class in C++.
+// The buffet::Any class can hold any C++ type, but both the setter and
+// getter sites need to know the actual type of data.
+// Note that C-style arrays when stored in Any are reduced to simple
+// data pointers. Any will not copy a contents of the array.
+//    const int data[] = [1,2,3];
+//    Any v(data);  // stores const int*, effectively "Any v(&data[0]);"
+
+// buffet::Any is a value type. Which means, the data is copied into it
+// and Any owns it. The owned object (stored by value) will be destroyed
+// when Any is cleared or reassigned. The contained value type must be
+// copy-constructible. You can also store pointers and references to objects.
+// Storing pointers is trivial. In order to store a reference, you can
+// use helper functions std::ref() and std::cref() to create non-const and
+// const references respectively. In such a case, the type of contained data
+// will be std::reference_wrapper<T>. See 'References' unit tests in
+// any_unittest.cc for examples.
+
+#ifndef BUFFET_ANY_H_
+#define BUFFET_ANY_H_
+
+#include "buffet/any_internal_impl.h"
+
+#include <algorithm>
+
+namespace buffet {
+
+class Any final {
+ public:
+  Any() = default;
+  // Standard copy constructor. This is a value-class container
+  // that must be copy-constructible and movable. The copy constructors
+  // should not be marked as explicit.
+  Any(const Any& rhs);
+  // Typed constructor that stores a value of type T in the Any.
+  template<class T>
+  Any(T value) {        // NOLINT(runtime/explicit)
+    data_buffer_.Assign(std::move(value));
+  }
+
+  // Not declaring the destructor as virtual since this is a sealed class
+  // and there is no need to introduce a virtual table to it.
+  ~Any();
+
+  // Assignment operators.
+  Any& operator=(const Any& rhs);
+  template<class T>
+  Any& operator=(T value) {
+    data_buffer_.Assign(std::move(value));
+    return *this;
+  }
+
+  // Checks if the given type DestType can be obtained from the Any.
+  // For example, to check if Any has a 'double' value in it:
+  //  any.IsTypeCompatible<double>()
+  template<typename DestType>
+  bool IsTypeCompatible() const {
+    // Make sure the requested type DestType conforms to the storage
+    // requirements of Any. We always store the data by value, which means we
+    // strip away any references as well as cv-qualifiers. So, if the user
+    // stores "const int&", we actually store just an "int".
+    // When calling IsTypeCompatible, we need to do a similar "type cleansing"
+    // to make sure the requested type matches the type of data actually stored,
+    // so this "canonical" type is used for type checking below.
+    using CanonicalDestType = typename std::decay<DestType>::type;
+    const std::type_info& ContainedTypeId = GetType();
+    if (typeid(CanonicalDestType) == ContainedTypeId)
+      return true;
+
+    if (!std::is_pointer<CanonicalDestType>::value)
+      return false;
+
+    // If asking for a const pointer from a variant containing non-const
+    // pointer, still satisfy the request. So, we need to remove the pointer
+    // specification first, then strip the const/volatile qualifiers, then
+    // re-add the pointer back, so "const int*" would become "int*".
+    using NonPointer = typename std::remove_pointer<CanonicalDestType>::type;
+    using CanonicalDestTypeNoConst = typename std::add_pointer<
+        typename std::remove_const<NonPointer>::type>::type;
+    using CanonicalDestTypeNoVolatile = typename std::add_pointer<
+        typename std::remove_volatile<NonPointer>::type>::type;
+    using CanonicalDestTypeNoConstOrVolatile = typename std::add_pointer<
+        typename std::remove_cv<NonPointer>::type>::type;
+
+    return typeid(CanonicalDestTypeNoConst) == ContainedTypeId ||
+           typeid(CanonicalDestTypeNoVolatile) == ContainedTypeId ||
+           typeid(CanonicalDestTypeNoConstOrVolatile) == ContainedTypeId;
+  }
+
+  // Returns immutable data contained in Any.
+  // Aborts if Any doesn't contain a value of type T, or trivially
+  // convertible to/compatible with it.
+  template<typename T>
+  const T& Get() const {
+    CHECK(IsTypeCompatible<T>()) << "Requesting value of type "
+                                 << typeid(T).name()
+                                 << " from variant containing "
+                                 << GetType().name();
+    return data_buffer_.GetData<T>();
+  }
+
+  // Returns a pointer to mutable value of type T contained within Any.
+  // No data copying is made, the data pointed to is still owned by Any.
+  // If Any doesn't contain a value of type T, or trivially
+  // convertible/compatible to/with it, then it returns nullptr.
+  template<typename T>
+  T* GetPtr() {
+    if (!IsTypeCompatible<T>())
+      return nullptr;
+    return &(data_buffer_.GetData<T>());
+  }
+
+  // Returns immutable data contained in Any.
+  // If the Any doesn't contain a compatible value, the provided default
+  // |def_val| is returned instead.
+  template<typename T>
+  const T& TryGet(typename std::decay<T>::type const& def_val) const {
+    if (!IsTypeCompatible<T>())
+      return def_val;
+    return data_buffer_.GetData<T>();
+  }
+
+  // A convenience specialization of the above function where the default
+  // value of type T is returned in case the underlying Get() fails.
+  template<typename T>
+  const T& TryGet() const {
+    return TryGet<T>(typename std::decay<T>::type());
+  }
+
+
+  // Returns the type information about the contained data. For most cases,
+  // instead of using this function, you should be calling IsTypeCompatible<>().
+  const std::type_info& GetType() const;
+  // Swaps the value of this object with that of |other|.
+  void Swap(Any& other);
+  // Checks if Any is empty, that is, not containing a value of any type.
+  bool IsEmpty() const;
+  // Clears the Any and destroys any contained object. Makes it empty.
+  void Clear();
+  // Checks if Any contains a type convertible to integer.
+  // Any type that match std::is_integral<T> and std::is_enum<T> is accepted.
+  // That includes signed and unsigned char, short, int, long, etc as well as
+  // 'bool' and enumerated types.
+  // For 'integer' type, you can call GetAsInteger to do implicit type
+  // conversion to intmax_t.
+  bool IsConvertibleToInteger() const;
+  // For integral types and enums contained in the Any, get the integer value
+  // of data. This is a useful function to obtain an integer value when
+  // any can possibly have unspecified integer, such as 'short', 'unsigned long'
+  // and so on.
+  intmax_t GetAsInteger() const;
+
+ private:
+  // The data buffer for contained object.
+  internal_details::Buffer data_buffer_;
+};
+
+}  // namespace buffet
+
+namespace std {
+
+// Specialize std::swap() algorithm for buffet::Any class.
+inline void swap(buffet::Any& lhs, buffet::Any& rhs) {
+  lhs.Swap(rhs);
+}
+
+}  // namespace std
+
+#endif  // BUFFET_ANY_H_
+