libchromeos: Move Any from Buffet to libchromeos. Move the Any class from Buffet to libchromeos and changed its namespace from buffet:: to chromeos:: Updated the rest of Buffet code to with the changes to the class's namespace and header file location. Also, now that move constructors are officially allowed by Google C++ coding style for project with C++11 feature support, added back the move constructor to Any as per http://crbug.com/387902 BUG=chromium:405714,chromium:387902 TEST=USE=buffet ./build_packages Change-Id: Id007f51b874934e4f6428fe90674495edeb79107 Reviewed-on: https://chromium-review.googlesource.com/213831 Tested-by: Alex Vakulenko <avakulenko@chromium.org> Reviewed-by: Ben Chan <benchan@chromium.org> Commit-Queue: Alex Vakulenko <avakulenko@chromium.org>
diff --git a/buffet/any.cc b/buffet/any.cc deleted file mode 100644 index 9ce0ce2..0000000 --- a/buffet/any.cc +++ /dev/null
@@ -1,51 +0,0 @@ -// 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. - -#include "buffet/any.h" - -#include <algorithm> - -namespace buffet { - -Any::Any(const Any& rhs) : data_buffer_(rhs.data_buffer_) { -} - -Any::~Any() { -} - -Any& Any::operator=(const Any& rhs) { - data_buffer_ = rhs.data_buffer_; - return *this; -} - -const std::type_info& Any::GetType() const { - if (!IsEmpty()) - return data_buffer_.GetDataPtr()->GetType(); - - struct NullType {}; // Special helper type representing an empty variant. - return typeid(NullType); -} - -void Any::Swap(Any& other) { - std::swap(data_buffer_, other.data_buffer_); -} - -bool Any::IsEmpty() const { - return data_buffer_.IsEmpty(); -} - -void Any::Clear() { - data_buffer_.Clear(); -} - -bool Any::IsConvertibleToInteger() const { - return !IsEmpty() && data_buffer_.GetDataPtr()->IsConvertibleToInteger(); -} - -intmax_t Any::GetAsInteger() const { - CHECK(!IsEmpty()) << "Must not be called on an empty Any"; - return data_buffer_.GetDataPtr()->GetAsInteger(); -} - -} // namespace buffet
diff --git a/buffet/any.h b/buffet/any.h deleted file mode 100644 index 5ab249c..0000000 --- a/buffet/any.h +++ /dev/null
@@ -1,174 +0,0 @@ -// 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_ -
diff --git a/buffet/any_internal_impl.h b/buffet/any_internal_impl.h deleted file mode 100644 index d875e3b..0000000 --- a/buffet/any_internal_impl.h +++ /dev/null
@@ -1,215 +0,0 @@ -// 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. - -// Internal implementation of buffet::Any class. - -#ifndef BUFFET_ANY_INTERNAL_IMPL_H_ -#define BUFFET_ANY_INTERNAL_IMPL_H_ - -#include <type_traits> -#include <typeinfo> -#include <utility> - -#include <base/logging.h> - -namespace buffet { - -namespace internal_details { - -// An extension to std::is_convertible to allow conversion from an enum to -// an integral type which std::is_convertible does not indicate as supported. -template <typename From, typename To> -struct IsConvertible : public std::integral_constant<bool, - std::is_convertible<From, To>::value || - (std::is_enum<From>::value && std::is_integral<To>::value)> { -}; -// TryConvert is a helper function that does a safe compile-time conditional -// type cast between data types that may not be always convertible. -// From and To are the source and destination types. -// The function returns true if conversion was possible/successful. -template <typename From, typename To> -inline typename std::enable_if<IsConvertible<From, To>::value, bool>::type -TryConvert(const From& in, To* out) { - *out = static_cast<To>(in); - return true; -} -template <typename From, typename To> -inline typename std::enable_if<!IsConvertible<From, To>::value, bool>::type -TryConvert(const From& in, To* out) { - return false; -} - -class Buffer; // Forward declaration of data buffer container. - -// Abstract base class for contained variant data. -struct Data { - virtual ~Data() {} - // Returns the type information for the contained data. - virtual const std::type_info& GetType() const = 0; - // Copies the contained data to the output |buffer|. - virtual void CopyTo(Buffer* buffer) const = 0; - // Checks if the contained data is an integer type (not necessarily an 'int'). - virtual bool IsConvertibleToInteger() const = 0; - // Gets the contained integral value as an integer. - virtual intmax_t GetAsInteger() const = 0; -}; - -// Concrete implementation of variant data of type T. -template<typename T> -struct TypedData : public Data { - explicit TypedData(const T& value) : value_(value) {} - - const std::type_info& GetType() const override { return typeid(T); } - void CopyTo(Buffer* buffer) const override; - bool IsConvertibleToInteger() const override { - return std::is_integral<T>::value || std::is_enum<T>::value; - } - intmax_t GetAsInteger() const override { - intmax_t int_val = 0; - bool converted = TryConvert(value_, &int_val); - CHECK(converted) << "Unable to convert value of type " << typeid(T).name() - << " to integer"; - return int_val; - } - // Special method to copy data of the same type - // without reallocating the buffer. - void FastAssign(const T& source) { value_ = source; } - - T value_; -}; - -// Buffer class that stores the contained variant data. -// To improve performance and reduce memory fragmentation, small variants -// are stored in pre-allocated memory buffers that are part of the Any class. -// If the memory requirements are larger than the set limit or the type is -// non-trivially copyable, then the contained class is allocated in a separate -// memory block and the pointer to that memory is contained within this memory -// buffer class. -class Buffer { - public: - enum StorageType { kExternal, kContained }; - Buffer() : external_ptr_(nullptr), storage_(kExternal) {} - ~Buffer() { - Clear(); - } - - Buffer(const Buffer& rhs) : Buffer() { - rhs.CopyTo(this); - } - Buffer& operator=(const Buffer& rhs) { - rhs.CopyTo(this); - return *this; - } - - // Returns the underlying pointer to contained data. Uses either the pointer - // or the raw data depending on |storage_| type. - inline Data* GetDataPtr() { - return (storage_ == kExternal) ? - external_ptr_ : reinterpret_cast<Data*>(contained_buffer_); - } - inline const Data* GetDataPtr() const { - return (storage_ == kExternal) ? - external_ptr_ : reinterpret_cast<const Data*>(contained_buffer_); - } - - // Destroys the contained object (and frees memory if needed). - void Clear() { - Data* data = GetDataPtr(); - if (storage_ == kExternal) { - delete data; - } else { - // Call the destructor manually, since the object was constructed inline - // in the pre-allocated buffer. We still need to call the destructor - // to free any associated resources, but we can't call delete |data| here. - data->~Data(); - } - external_ptr_ = nullptr; - storage_ = kExternal; - } - - // Stores a value of type T. - template<typename T> - void Assign(T value) { - using Type = typename std::decay<T>::type; - using DataType = TypedData<Type>; - Data* ptr = GetDataPtr(); - if (ptr && ptr->GetType() == typeid(Type)) { - // We assign the data to the variant container, which already - // has the data of the same type. Do fast copy with no memory - // reallocation. - DataType* typed_ptr = static_cast<DataType*>(ptr); - typed_ptr->FastAssign(value); - } else { - Clear(); - // TODO(avakulenko): [see crbug.com/379833] - // Unfortunately, GCC doesn't support std::is_trivially_copyable<T> yet, - // so using std::is_trivial instead, which is a bit more restrictive. - // Once GCC has support for is_trivially_copyable, update the following. - if (!std::is_trivial<Type>::value || - sizeof(DataType) > sizeof(contained_buffer_)) { - // If it is too big or not trivially copyable, allocate it separately. - external_ptr_ = new DataType(value); - storage_ = kExternal; - } else { - // Otherwise just use the pre-allocated buffer. - DataType* address = reinterpret_cast<DataType*>(contained_buffer_); - // Make sure we still call the copy constructor. - // Call the constructor manually by using placement 'new'. - new (address) DataType(value); - storage_ = kContained; - } - } - } - - // Helper methods to retrieve a reference to contained data. - // These assume that type checking has already been performed by Any - // so the type cast is valid and will succeed. - template<typename T> - const T& GetData() const { - using DataType = internal_details::TypedData<typename std::decay<T>::type>; - return static_cast<const DataType*>(GetDataPtr())->value_; - } - template<typename T> - T& GetData() { - using DataType = internal_details::TypedData<typename std::decay<T>::type>; - return static_cast<DataType*>(GetDataPtr())->value_; - } - - // Returns true if the buffer has no contained data. - bool IsEmpty() const { - return (storage_ == kExternal && external_ptr_ == nullptr); - } - - // Copies the data from the current buffer into the |destination|. - void CopyTo(Buffer* destination) const { - if (IsEmpty()) { - destination->Clear(); - } else { - GetDataPtr()->CopyTo(destination); - } - } - - union { - // |external_ptr_| is a pointer to a larger object allocated in - // a separate memory block. - Data* external_ptr_; - // |contained_buffer_| is a pre-allocated buffer for smaller/simple objects. - // Pre-allocate enough memory to store objects as big as "double". - unsigned char contained_buffer_[sizeof(TypedData<double>)]; - }; - // Depending on a value of |storage_|, either |external_ptr_| or - // |contained_buffer_| above is used to get a pointer to memory containing - // the variant data. - StorageType storage_; // Declare after the union to eliminate member padding. -}; - -template<typename T> -void TypedData<T>::CopyTo(Buffer* buffer) const { buffer->Assign(value_); } - -} // namespace internal_details - -} // namespace buffet - -#endif // BUFFET_ANY_INTERNAL_IMPL_H_ -
diff --git a/buffet/any_internal_impl_unittest.cc b/buffet/any_internal_impl_unittest.cc deleted file mode 100644 index 8c2fa58..0000000 --- a/buffet/any_internal_impl_unittest.cc +++ /dev/null
@@ -1,114 +0,0 @@ -// 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. - -#include <string> - -#include <gtest/gtest.h> - -#include "buffet/any.h" - -using buffet::internal_details::Buffer; - -TEST(Buffer, Empty) { - Buffer buffer; - EXPECT_TRUE(buffer.IsEmpty()); - EXPECT_EQ(Buffer::kExternal, buffer.storage_); - EXPECT_EQ(nullptr, buffer.GetDataPtr()); -} - -TEST(Buffer, Store_Int) { - Buffer buffer; - buffer.Assign(2); - EXPECT_FALSE(buffer.IsEmpty()); - EXPECT_EQ(Buffer::kContained, buffer.storage_); - EXPECT_EQ(typeid(int), buffer.GetDataPtr()->GetType()); -} - -TEST(Buffer, Store_Double) { - Buffer buffer; - buffer.Assign(2.3); - EXPECT_FALSE(buffer.IsEmpty()); - EXPECT_EQ(Buffer::kContained, buffer.storage_); - EXPECT_EQ(typeid(double), buffer.GetDataPtr()->GetType()); -} - -TEST(Buffer, Store_Pointers) { - Buffer buffer; - // nullptr - buffer.Assign(nullptr); - EXPECT_FALSE(buffer.IsEmpty()); - EXPECT_EQ(Buffer::kContained, buffer.storage_); - EXPECT_EQ(typeid(std::nullptr_t), buffer.GetDataPtr()->GetType()); - - // char * - buffer.Assign("abcd"); - EXPECT_FALSE(buffer.IsEmpty()); - EXPECT_EQ(Buffer::kContained, buffer.storage_); - EXPECT_EQ(typeid(const char*), buffer.GetDataPtr()->GetType()); - - // pointer to non-trivial object - class NonTrivial { - public: - virtual ~NonTrivial() {} - } non_trivial; - buffer.Assign(&non_trivial); - EXPECT_FALSE(buffer.IsEmpty()); - EXPECT_EQ(Buffer::kContained, buffer.storage_); - EXPECT_EQ(typeid(NonTrivial*), buffer.GetDataPtr()->GetType()); -} - -TEST(Buffer, Store_NonTrivialObjects) { - class NonTrivial { - public: - virtual ~NonTrivial() {} - } non_trivial; - Buffer buffer; - buffer.Assign(non_trivial); - EXPECT_FALSE(buffer.IsEmpty()); - EXPECT_EQ(Buffer::kExternal, buffer.storage_); - EXPECT_EQ(typeid(NonTrivial), buffer.GetDataPtr()->GetType()); -} - -TEST(Buffer, Store_Objects) { - Buffer buffer; - - struct Small { - double d; - } small = {}; - buffer.Assign(small); - EXPECT_FALSE(buffer.IsEmpty()); - EXPECT_EQ(Buffer::kContained, buffer.storage_); - EXPECT_EQ(typeid(Small), buffer.GetDataPtr()->GetType()); - - struct Large { - char c[10]; - } large = {}; - buffer.Assign(large); - EXPECT_FALSE(buffer.IsEmpty()); - EXPECT_EQ(Buffer::kExternal, buffer.storage_); - EXPECT_EQ(typeid(Large), buffer.GetDataPtr()->GetType()); -} - -TEST(Buffer, Copy) { - Buffer buffer1; - Buffer buffer2; - - buffer1.Assign(30); - buffer1.CopyTo(&buffer2); - EXPECT_FALSE(buffer1.IsEmpty()); - EXPECT_FALSE(buffer2.IsEmpty()); - EXPECT_EQ(typeid(int), buffer1.GetDataPtr()->GetType()); - EXPECT_EQ(typeid(int), buffer2.GetDataPtr()->GetType()); - EXPECT_EQ(30, buffer1.GetData<int>()); - EXPECT_EQ(30, buffer2.GetData<int>()); - - buffer1.Assign(std::string("abc")); - buffer1.CopyTo(&buffer2); - EXPECT_FALSE(buffer1.IsEmpty()); - EXPECT_FALSE(buffer2.IsEmpty()); - EXPECT_EQ(typeid(std::string), buffer1.GetDataPtr()->GetType()); - EXPECT_EQ(typeid(std::string), buffer2.GetDataPtr()->GetType()); - EXPECT_EQ("abc", buffer1.GetData<std::string>()); - EXPECT_EQ("abc", buffer2.GetData<std::string>()); -}
diff --git a/buffet/any_unittest.cc b/buffet/any_unittest.cc deleted file mode 100644 index eaf3ce1..0000000 --- a/buffet/any_unittest.cc +++ /dev/null
@@ -1,245 +0,0 @@ -// 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. - -#include <algorithm> -#include <functional> -#include <string> -#include <vector> - -#include <gtest/gtest.h> - -#include "buffet/any.h" - -using buffet::Any; - -TEST(Any, Empty) { - Any val; - EXPECT_TRUE(val.IsEmpty()); - - Any val2 = val; - EXPECT_TRUE(val.IsEmpty()); - EXPECT_TRUE(val2.IsEmpty()); -} - -TEST(Any, SimpleTypes) { - Any val(20); - EXPECT_FALSE(val.IsEmpty()); - EXPECT_TRUE(val.IsTypeCompatible<int>()); - EXPECT_EQ(20, val.Get<int>()); - - Any val2(3.1415926); - EXPECT_FALSE(val2.IsEmpty()); - EXPECT_TRUE(val2.IsTypeCompatible<double>()); - EXPECT_FALSE(val2.IsTypeCompatible<int>()); - EXPECT_DOUBLE_EQ(3.1415926, val2.Get<double>()); - - Any val3(std::string("blah")); - EXPECT_TRUE(val3.IsTypeCompatible<std::string>()); - EXPECT_EQ("blah", val3.Get<std::string>()); -} - -TEST(Any, Clear) { - Any val('x'); - EXPECT_FALSE(val.IsEmpty()); - EXPECT_EQ('x', val.Get<char>()); - - val.Clear(); - EXPECT_TRUE(val.IsEmpty()); -} - -TEST(Any, Assignments) { - Any val(20); - EXPECT_EQ(20, val.Get<int>()); - - val = 3.1415926; - EXPECT_FALSE(val.IsEmpty()); - EXPECT_TRUE(val.IsTypeCompatible<double>()); - EXPECT_DOUBLE_EQ(3.1415926, val.Get<double>()); - - val = std::string("blah"); - EXPECT_EQ("blah", val.Get<std::string>()); - - Any val2; - EXPECT_TRUE(val2.IsEmpty()); - val2 = val; - EXPECT_FALSE(val.IsEmpty()); - EXPECT_FALSE(val2.IsEmpty()); - EXPECT_EQ("blah", val.Get<std::string>()); - EXPECT_EQ("blah", val2.Get<std::string>()); - val.Clear(); - EXPECT_TRUE(val.IsEmpty()); - EXPECT_EQ("blah", val2.Get<std::string>()); - val2.Clear(); - EXPECT_TRUE(val2.IsEmpty()); - - val = std::vector<int>{100, 20, 3}; - auto v = val.Get<std::vector<int>>(); - EXPECT_EQ(100, v[0]); - EXPECT_EQ(20, v[1]); - EXPECT_EQ(3, v[2]); -} - -TEST(Any, Enums) { - enum class Dummy { foo, bar, baz }; - Any val(Dummy::bar); - EXPECT_FALSE(val.IsEmpty()); - EXPECT_TRUE(val.IsConvertibleToInteger()); - EXPECT_EQ(Dummy::bar, val.Get<Dummy>()); - EXPECT_EQ(1, val.GetAsInteger()); - - val = Dummy::baz; - EXPECT_EQ(2, val.GetAsInteger()); - - val = Dummy::foo; - EXPECT_EQ(0, val.GetAsInteger()); -} - -TEST(Any, Integers) { - Any val(14); - EXPECT_TRUE(val.IsConvertibleToInteger()); - EXPECT_EQ(14, val.Get<int>()); - EXPECT_EQ(14, val.GetAsInteger()); - - val = '\x40'; - EXPECT_TRUE(val.IsConvertibleToInteger()); - EXPECT_EQ(64, val.Get<char>()); - EXPECT_EQ(64, val.GetAsInteger()); - - val = static_cast<uint16_t>(65535); - EXPECT_TRUE(val.IsConvertibleToInteger()); - EXPECT_EQ(65535, val.Get<uint16_t>()); - EXPECT_EQ(65535, val.GetAsInteger()); - - val = static_cast<uint64_t>(0xFFFFFFFFFFFFFFFFULL); - EXPECT_TRUE(val.IsConvertibleToInteger()); - EXPECT_EQ(0xFFFFFFFFFFFFFFFFULL, val.Get<uint64_t>()); - EXPECT_EQ(-1, val.GetAsInteger()); - - val = "abc"; - EXPECT_FALSE(val.IsConvertibleToInteger()); - - int a = 5; - val = &a; - EXPECT_FALSE(val.IsConvertibleToInteger()); -} - -TEST(Any, Pointers) { - Any val("abc"); // const char* - EXPECT_FALSE(val.IsTypeCompatible<char*>()); - EXPECT_TRUE(val.IsTypeCompatible<const char*>()); - EXPECT_FALSE(val.IsTypeCompatible<volatile char*>()); - EXPECT_TRUE(val.IsTypeCompatible<volatile const char*>()); - EXPECT_STREQ("abc", val.Get<const char*>()); - - int a = 10; - val = &a; - EXPECT_TRUE(val.IsTypeCompatible<int*>()); - EXPECT_TRUE(val.IsTypeCompatible<const int*>()); - EXPECT_TRUE(val.IsTypeCompatible<volatile int*>()); - EXPECT_TRUE(val.IsTypeCompatible<volatile const int*>()); - EXPECT_EQ(10, *val.Get<const int*>()); - *val.Get<int*>() = 3; - EXPECT_EQ(3, a); -} - -TEST(Any, Arrays) { - // The following test are here to validate the array-to-pointer decay rules. - // Since Any does not store the contents of a C-style array, just a pointer - // to the data, putting array data into Any could be dangerous. - // Make sure the array's lifetime exceeds that of an Any containing the - // pointer to the array data. - // If you want to store the array with data, use corresponding value types - // such as std::vector or a struct containing C-style array as a member. - - int int_array[] = {1, 2, 3}; // int* - Any val = int_array; - EXPECT_TRUE(val.IsTypeCompatible<int*>()); - EXPECT_TRUE(val.IsTypeCompatible<const int*>()); - EXPECT_TRUE(val.IsTypeCompatible<int[]>()); - EXPECT_TRUE(val.IsTypeCompatible<const int[]>()); - EXPECT_EQ(3, val.Get<int*>()[2]); - - const int const_int_array[] = {10, 20, 30}; // const int* - val = const_int_array; - EXPECT_FALSE(val.IsTypeCompatible<int*>()); - EXPECT_TRUE(val.IsTypeCompatible<const int*>()); - EXPECT_FALSE(val.IsTypeCompatible<int[]>()); - EXPECT_TRUE(val.IsTypeCompatible<const int[]>()); - EXPECT_EQ(30, val.Get<const int*>()[2]); -} - -TEST(Any, References) { - // Passing references to object via Any might be error-prone or the - // semantics could be unfamiliar to other developers. In many cases, - // using pointers instead of references are more conventional and easier - // to understand. Even though the cases of passing references are quite - // explicit on both storing and retrieving ends, you might want to - // use pointers instead anyway. - - int a = 5; - Any val(std::ref(a)); // int& - EXPECT_EQ(5, val.Get<std::reference_wrapper<int>>().get()); - val.Get<std::reference_wrapper<int>>().get() = 7; - EXPECT_EQ(7, val.Get<std::reference_wrapper<int>>().get()); - EXPECT_EQ(7, a); - - Any val2(std::cref(a)); // const int& - EXPECT_EQ(7, val2.Get<std::reference_wrapper<const int>>().get()); - - a = 10; - EXPECT_EQ(10, val.Get<std::reference_wrapper<int>>().get()); - EXPECT_EQ(10, val2.Get<std::reference_wrapper<const int>>().get()); -} - -TEST(Any, CustomTypes) { - struct Person { - std::string name; - int age; - }; - Any val(Person{"Jack", 40}); - Any val2 = val; - EXPECT_EQ("Jack", val.Get<Person>().name); - val.GetPtr<Person>()->name = "Joe"; - val.GetPtr<Person>()->age /= 2; - EXPECT_EQ("Joe", val.Get<Person>().name); - EXPECT_EQ(20, val.Get<Person>().age); - EXPECT_EQ("Jack", val2.Get<Person>().name); - EXPECT_EQ(40, val2.Get<Person>().age); -} - -TEST(Any, Swap) { - Any val(12); - Any val2(2.7); - EXPECT_EQ(12, val.Get<int>()); - EXPECT_EQ(2.7, val2.Get<double>()); - - val.Swap(val2); - EXPECT_EQ(2.7, val.Get<double>()); - EXPECT_EQ(12, val2.Get<int>()); - - std::swap(val, val2); - EXPECT_EQ(12, val.Get<int>()); - EXPECT_EQ(2.7, val2.Get<double>()); -} - -TEST(Any, TypeMismatch) { - Any val(12); - EXPECT_DEATH(val.Get<double>(), - "Requesting value of type \\w+ from variant containing \\w+"); - - val = std::string("123"); - EXPECT_DEATH(val.GetAsInteger(), - "Unable to convert value of type \\w+ to integer"); - - Any empty; - EXPECT_DEATH(empty.GetAsInteger(), "Must not be called on an empty Any"); -} - -TEST(Any, TryGet) { - Any val(12); - Any empty; - EXPECT_EQ("dummy", val.TryGet<std::string>("dummy")); - EXPECT_EQ(12, val.TryGet<int>(17)); - EXPECT_EQ(17, empty.TryGet<int>(17)); -}
diff --git a/buffet/buffet.gyp b/buffet/buffet.gyp index 74c1564..f02e494 100644 --- a/buffet/buffet.gyp +++ b/buffet/buffet.gyp
@@ -15,7 +15,6 @@ 'target_name': 'buffet_common', 'type': 'static_library', 'sources': [ - 'any.cc', 'commands/command_definition.cc', 'commands/command_dictionary.cc', 'commands/command_instance.cc', @@ -76,8 +75,6 @@ }, 'includes': ['../common-mk/common_test.gypi'], 'sources': [ - 'any_unittest.cc', - 'any_internal_impl_unittest.cc', 'buffet_testrunner.cc', 'commands/command_definition_unittest.cc', 'commands/command_dictionary_unittest.cc',
diff --git a/buffet/commands/prop_types.cc b/buffet/commands/prop_types.cc index 694d74e..f4de059 100644 --- a/buffet/commands/prop_types.cc +++ b/buffet/commands/prop_types.cc
@@ -11,6 +11,7 @@ #include <base/json/json_writer.h> #include <base/logging.h> #include <base/values.h> +#include <chromeos/any.h> #include <chromeos/string_utils.h> #include "buffet/commands/object_schema.h" @@ -149,7 +150,7 @@ return val->FromJson(value, error) && ValidateConstraints(*val, error); } -bool PropType::ValidateValue(const Any& value, +bool PropType::ValidateValue(const chromeos::Any& value, chromeos::ErrorPtr* error) const { std::shared_ptr<PropValue> val = CreateValue(value); CHECK(val) << "Failed to create value object";
diff --git a/buffet/commands/prop_types.h b/buffet/commands/prop_types.h index 506c822..86a2960 100644 --- a/buffet/commands/prop_types.h +++ b/buffet/commands/prop_types.h
@@ -13,6 +13,7 @@ #include <utility> #include <vector> +#include <chromeos/any.h> #include <chromeos/error.h> #include "buffet/commands/prop_constraints.h" @@ -81,7 +82,8 @@ // Creates an instance of associated value object, using the parameter // type as a factory class. virtual std::shared_ptr<PropValue> CreateValue() const = 0; - virtual std::shared_ptr<PropValue> CreateValue(const Any& val) const = 0; + virtual std::shared_ptr<PropValue> CreateValue( + const chromeos::Any& val) const = 0; // Saves the parameter type definition as a JSON object. // If |full_schema| is set to true, the full type definition is saved, @@ -122,7 +124,8 @@ bool ValidateValue(const base::Value* value, chromeos::ErrorPtr* error) const; // Similar to the above method, but uses Any as the value container. - bool ValidateValue(const Any& value, chromeos::ErrorPtr* error) const; + bool ValidateValue(const chromeos::Any& value, + chromeos::ErrorPtr* error) const; // Additional helper static methods to help with converting a type enum // value into a string and back. @@ -186,7 +189,8 @@ std::shared_ptr<PropValue> CreateValue() const override { return std::make_shared<Value>(this); } - std::shared_ptr<PropValue> CreateValue(const Any& v) const override { + std::shared_ptr<PropValue> CreateValue( + const chromeos::Any& v) const override { auto value = std::make_shared<Value>(this); value->SetValue(v.Get<T>()); return std::move(value);
diff --git a/buffet/commands/prop_values.h b/buffet/commands/prop_values.h index f568dd8..106ab1d 100644 --- a/buffet/commands/prop_values.h +++ b/buffet/commands/prop_values.h
@@ -9,9 +9,9 @@ #include <memory> #include <string> +#include <chromeos/any.h> #include <chromeos/error.h> -#include "buffet/any.h" #include "buffet/commands/schema_utils.h" namespace base { @@ -103,7 +103,7 @@ chromeos::ErrorPtr* error) = 0; // Returns the contained C++ value as Any. - virtual Any GetValueAsAny() const = 0; + virtual chromeos::Any GetValueAsAny() const = 0; // Return the type definition of this value. const PropType* GetPropType() const { return type_; } @@ -149,7 +149,7 @@ } // Helper methods to get and set the C++ representation of the value. - Any GetValueAsAny() const override { return value_; } + chromeos::Any GetValueAsAny() const override { return value_; } const T& GetValue() const { return value_; } void SetValue(T value) { value_ = std::move(value); }