summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno de Oliveira Abinader <bruno@mapbox.com>2018-07-24 21:25:21 +0300
committerBruno de Oliveira Abinader <bruno@mapbox.com>2018-08-08 14:14:34 +0300
commit3952ff5c343844d76f75ede0afc8ddad55748a0d (patch)
treed19172ad104ba520f7f8d1d939a1690791606993
parent990b3b11b9427ffd86f693d3f4c3dd351891e5d0 (diff)
downloadqtlocation-mapboxgl-3952ff5c343844d76f75ede0afc8ddad55748a0d.tar.gz
[core] Replace unique_any with peer from mapbox-bindgen
-rw-r--r--cmake/core-files.cmake2
-rw-r--r--cmake/test-files.cmake2
-rw-r--r--include/mbgl/style/layer.hpp4
-rw-r--r--include/mbgl/style/source.hpp4
-rw-r--r--include/mbgl/util/peer.hpp111
-rw-r--r--include/mbgl/util/unique_any.hpp271
-rw-r--r--platform/android/src/style/sources/source.cpp4
-rw-r--r--platform/darwin/src/MGLStyle.mm4
-rw-r--r--test/util/peer.test.cpp194
-rw-r--r--test/util/unique_any.test.cpp218
10 files changed, 315 insertions, 499 deletions
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake
index addacc174d..2cfcb16771 100644
--- a/cmake/core-files.cmake
+++ b/cmake/core-files.cmake
@@ -679,6 +679,7 @@ set(MBGL_CORE_FILES
include/mbgl/util/logging.hpp
include/mbgl/util/noncopyable.hpp
include/mbgl/util/optional.hpp
+ include/mbgl/util/peer.hpp
include/mbgl/util/platform.hpp
include/mbgl/util/premultiply.hpp
include/mbgl/util/projection.hpp
@@ -692,7 +693,6 @@ set(MBGL_CORE_FILES
include/mbgl/util/traits.hpp
include/mbgl/util/tuple.hpp
include/mbgl/util/type_list.hpp
- include/mbgl/util/unique_any.hpp
include/mbgl/util/unitbezier.hpp
include/mbgl/util/util.hpp
include/mbgl/util/variant.hpp
diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake
index 1961d78dfc..2a679fc40b 100644
--- a/cmake/test-files.cmake
+++ b/cmake/test-files.cmake
@@ -137,6 +137,7 @@ set(MBGL_TEST_FILES
test/util/merge_lines.test.cpp
test/util/number_conversions.test.cpp
test/util/offscreen_texture.test.cpp
+ test/util/peer.test.cpp
test/util/position.test.cpp
test/util/projection.test.cpp
test/util/run_loop.test.cpp
@@ -147,7 +148,6 @@ set(MBGL_TEST_FILES
test/util/tile_range.test.cpp
test/util/timer.test.cpp
test/util/token.test.cpp
- test/util/unique_any.test.cpp
test/util/url.test.cpp
)
diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp
index 12494f5387..b5a4b63d2e 100644
--- a/include/mbgl/style/layer.hpp
+++ b/include/mbgl/style/layer.hpp
@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/util/noncopyable.hpp>
-#include <mbgl/util/unique_any.hpp>
+#include <mbgl/util/peer.hpp>
#include <mbgl/util/immutable.hpp>
#include <mbgl/style/layer_type.hpp>
#include <mbgl/style/types.hpp>
@@ -132,7 +132,7 @@ public:
// For use in SDK bindings, which store a reference to a platform-native peer
// object here, so that separately-obtained references to this object share
// identical platform-native peers.
- util::unique_any peer;
+ util::peer peer;
};
} // namespace style
diff --git a/include/mbgl/style/source.hpp b/include/mbgl/style/source.hpp
index 2f2838ade8..dc3a8d73fb 100644
--- a/include/mbgl/style/source.hpp
+++ b/include/mbgl/style/source.hpp
@@ -2,7 +2,7 @@
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/optional.hpp>
-#include <mbgl/util/unique_any.hpp>
+#include <mbgl/util/peer.hpp>
#include <mbgl/util/immutable.hpp>
#include <mbgl/style/types.hpp>
@@ -77,7 +77,7 @@ public:
// For use in SDK bindings, which store a reference to a platform-native peer
// object here, so that separately-obtained references to this object share
// identical platform-native peers.
- util::unique_any peer;
+ util::peer peer;
};
} // namespace style
diff --git a/include/mbgl/util/peer.hpp b/include/mbgl/util/peer.hpp
new file mode 100644
index 0000000000..a4abea0e88
--- /dev/null
+++ b/include/mbgl/util/peer.hpp
@@ -0,0 +1,111 @@
+#pragma once
+
+#include <type_traits>
+#include <utility>
+
+namespace mbgl {
+namespace util {
+
+class peer {
+public:
+ peer() = default;
+ peer(const peer&) = delete;
+
+ peer(peer&& other)
+ : vtable(other.vtable)
+ {
+ if (vtable) {
+ vtable->move(other.storage, storage);
+ }
+ other.vtable = nullptr;
+ }
+
+ template <class T>
+ peer(T&& value) {
+ using _Vt = std::decay_t<T>;
+ vtable = get_vtable<_Vt>();
+ new (&storage) _Vt(std::forward<T>(value));
+ }
+
+ ~peer() {
+ reset();
+ }
+
+ peer& operator=(peer&& rhs) {
+ peer(std::move(rhs)).swap(*this);
+ return *this;
+ }
+
+ void reset() {
+ if (vtable) {
+ vtable->destroy(storage);
+ vtable = nullptr;
+ }
+ }
+
+ void swap(peer& rhs) {
+ if (this == &rhs) {
+ return;
+ } else {
+ peer tmp(std::move(rhs));
+ rhs.vtable = vtable;
+ if (rhs.vtable) {
+ rhs.vtable->move(storage, rhs.storage);
+ }
+ vtable = tmp.vtable;
+ if (vtable) {
+ vtable->move(tmp.storage, storage);
+ }
+ }
+ }
+
+ bool has_value() const {
+ return vtable != nullptr;
+ }
+
+ template <class T>
+ T& get() {
+ return reinterpret_cast<T&>(storage);
+ }
+
+ template <class T>
+ T&& take() {
+ reset();
+ return std::move(get<T>());
+ }
+
+private:
+ using storage_t = std::aligned_storage_t<2*sizeof(void*), alignof(void*)>;
+
+ struct vtable {
+ virtual ~vtable() = default;
+ virtual void move(storage_t&, storage_t&) = 0;
+ virtual void destroy(storage_t&) = 0;
+ };
+
+ template <class T>
+ struct vtable_impl : public vtable {
+ static_assert(sizeof(T) <= sizeof(storage_t), "peer object is too big");
+
+ void move(storage_t& src, storage_t& dst) override {
+ new (&dst) T(std::move(reinterpret_cast<T&>(src)));
+ destroy(src);
+ }
+
+ void destroy(storage_t& s) override {
+ reinterpret_cast<T&>(s).~T();
+ }
+ };
+
+ template <class T>
+ static vtable* get_vtable() {
+ static vtable_impl<T> vtable;
+ return &vtable;
+ }
+
+ vtable* vtable = nullptr;
+ storage_t storage;
+};
+
+} // namespace util
+} // namespace mbgl
diff --git a/include/mbgl/util/unique_any.hpp b/include/mbgl/util/unique_any.hpp
deleted file mode 100644
index c7dc8b38ea..0000000000
--- a/include/mbgl/util/unique_any.hpp
+++ /dev/null
@@ -1,271 +0,0 @@
-#pragma once
-
-#include <typeinfo>
-#include <type_traits>
-#include <stdexcept>
-namespace mbgl {
-namespace util {
-
-class bad_any_cast : public std::bad_cast {
-public:
- const char* what() const noexcept override {
- return "bad any_cast<>()";
- }
-};
-/**
- * A variant of `std::any` for non-copyable types.
- *
- * Use `unique_any` for non-copyable types (e.g. `std::unique_ptr<T>`)
- * or to ensure that no copies are made of copyable types that are
- * moved in.
- *
- * `uniqe_any` differs from `std::any` in that it does not support copy construction
- * or copy assignment. It also does not require the contained type to be copy
- * constructible.
- *
- * The `any_cast<T>()` methods work similar to `std::any_cast<T>()` except that
- * non-copyable types may only be cast to references.
- *
- * Example usage:
- * unique_any u1(3);
- * auto u2 = unique_any(std::move(u1)); // u1 is moved from
- * int i = any_cast<int>(u2);
- *
- * unique_any u2;
- * u2 = std::unique_ptr<int>(new int);
- * std::unique_ptr<int> iPtr = any_cast<std::unique_ptr<int>>(std::move(u2));
- *
- * Inspired by linb::any (https://github.com/thelink2012/any) and the
- * libc++ implementation (https://github.com/llvm-mirror/libcxx).
- */
-class unique_any final
-{
-public:
- unique_any() = default;
-
- //Copy constructor (deleted)
- unique_any(const unique_any& rhs) = delete;
-
- unique_any(unique_any&& rhs) : vtable(rhs.vtable) {
- if (vtable) {
- vtable->move(std::move(rhs.storage), storage);
- }
- rhs.vtable = nullptr;
- }
-
- // Constructs with a direct-initilizated object of type ValueType
- template <typename ValueType,
- typename _Vt = std::decay_t<ValueType>,
- typename = std::enable_if_t<!std::is_same<_Vt, unique_any>::value> >
- unique_any(ValueType&& value) {
- create(std::forward<ValueType>(value));
- }
-
- ~unique_any() {
- reset();
- }
-
- unique_any& operator=(unique_any&& rhs) {
- unique_any(std::move(rhs)).swap(*this);
- return *this;
- }
-
- template <class ValueType,
- typename = std::enable_if_t<!std::is_same<std::decay_t<ValueType>, unique_any>::value> >
- unique_any& operator=(ValueType&& rhs) {
- unique_any(std::forward<ValueType>(rhs)).swap(*this);
- return *this;
- }
-
- void reset() {
- if (vtable) {
- vtable->destroy(storage);
- vtable = nullptr;
- }
- }
-
- void swap(unique_any& rhs) {
- if (this == &rhs) {
- return;
- } else {
- unique_any tmp(std::move(rhs));
- rhs.vtable = vtable;
- if (rhs.vtable) {
- rhs.vtable->move(std::move(storage), rhs.storage);
- }
- vtable = tmp.vtable;
- if (vtable) {
- vtable->move(std::move(tmp.storage), storage);
- }
- }
- }
-
- const std::type_info& type() const {
- return !has_value()? typeid(void) : vtable->type();
- }
-
- bool has_value() const {
- return vtable != nullptr;
- }
-
-private:
-
- union Storage {
- using StackStorage = std::aligned_storage_t<3*sizeof(void*), std::alignment_of<void*>::value>;
- Storage() = default;
-
- void * dynamic { nullptr };
- StackStorage stack;
- };
-
- template<typename T>
- struct AllocateOnStack : std::integral_constant<bool,
- sizeof(T) <= sizeof(Storage::stack)
- && std::alignment_of<T>::value <= std::alignment_of<Storage::StackStorage>::value
- && std::is_nothrow_move_constructible<T>::value> {
- };
-
- struct VTable {
- virtual ~VTable() = default;
- virtual void move(Storage&& src, Storage& dest) = 0;
- virtual void destroy(Storage&) = 0;
- virtual const std::type_info& type() = 0;
- };
-
- template <typename ValueType>
- struct VTableHeap : public VTable {
- void move(Storage&& src, Storage& dest) override {
- dest.dynamic = src.dynamic;
- src.dynamic = nullptr;
- }
-
- void destroy(Storage& s) override {
- delete reinterpret_cast<ValueType*>(s.dynamic);
- }
-
- const std::type_info& type() override {
- return typeid(ValueType);
- }
- };
-
- template <typename ValueType>
- struct VTableStack : public VTable {
- void move(Storage&& src, Storage& dest) override {
- new (&dest.stack) ValueType(std::move(reinterpret_cast<ValueType&>(src.stack)));
- destroy(src);
- }
-
- void destroy(Storage& s) override {
- reinterpret_cast<ValueType&>(s.stack).~ValueType();
- }
-
- const std::type_info& type() override {
- return typeid(ValueType);
- }
- };
-
- template <typename ValueType>
- static VTable* vtableForType() {
- using VTableType = std::conditional_t<AllocateOnStack<ValueType>::value, VTableStack<ValueType>, VTableHeap<ValueType> >;
- static VTableType vtable;
- return &vtable;
- }
-
- template <typename ValueType, typename _Vt>
- std::enable_if_t<AllocateOnStack<_Vt>::value>
- createStorage(ValueType&& value) {
- new (&storage.stack) _Vt(std::forward<ValueType>(value));
- }
-
- template <typename ValueType, typename _Vt>
- std::enable_if_t<!AllocateOnStack<_Vt>::value>
- createStorage(ValueType&& value) {
- storage.dynamic = new _Vt(std::forward<ValueType>(value));
- }
-
- template <typename ValueType>
- void create(ValueType&& value) {
- using _Vt = std::decay_t<ValueType>;
- vtable = vtableForType<_Vt>();
- createStorage<ValueType, _Vt>(std::forward<ValueType>(value));
- }
-
- VTable* vtable { nullptr };
- Storage storage;
-
-protected:
- template<class ValueType>
- friend const ValueType* any_cast(const unique_any* operand) ;
-
- template<class ValueType>
- friend ValueType* any_cast(unique_any* operand) ;
-
- template<typename ValueType, typename _Vt = std::decay_t<ValueType> >
- ValueType* cast()
- {
- return reinterpret_cast<ValueType *>(
- AllocateOnStack<_Vt>::value ? &storage.stack : storage.dynamic);
- }
-};
-
-template<typename ValueType>
-inline const ValueType* any_cast(const unique_any* any)
-{
- return any_cast<ValueType>(const_cast<unique_any *>(any));
-}
-
-template<typename ValueType>
-inline ValueType* any_cast(unique_any* any)
-{
- if(any == nullptr || any->type() != typeid(ValueType))
- return nullptr;
- else
- return any->cast<ValueType>();
-}
-
-template<typename ValueType, typename _Vt = std::decay_t<ValueType> >
-inline ValueType any_cast(const unique_any& any)
-{
- static_assert(std::is_constructible<ValueType, const _Vt&>::value,
- "any_cast type can't construct copy of contained object");
- auto temp = any_cast<_Vt>(&any);
- if (temp == nullptr) {
- throw bad_any_cast();
- }
- return static_cast<ValueType>(*temp);
-}
-
-template<typename ValueType, typename _Vt = std::decay_t<ValueType> >
-inline ValueType any_cast(unique_any& any)
-{
- static_assert(std::is_constructible<ValueType, const _Vt&>::value,
- "any_cast type can't construct copy of contained object");
- auto temp = any_cast<_Vt>(&any);
- if (temp == nullptr) {
- throw bad_any_cast();
- }
- return static_cast<ValueType>(*temp);
-}
-
-template<typename ValueType, typename _Vt = std::remove_cv_t<ValueType> >
-inline ValueType any_cast(unique_any&& any)
-{
- auto temp = any_cast<_Vt>(&any);
- if (temp == nullptr) {
- throw bad_any_cast();
- }
- auto retValue = static_cast<ValueType>(std::move(*temp));
- any.reset();
- return std::move(retValue);
-}
-
-} // namespace util
-} // namespace mbgl
-
-namespace std {
-
-inline void swap(mbgl::util::unique_any& lhs, mbgl::util::unique_any& rhs) {
- lhs.swap(rhs);
-}
-
-} // namespace std
diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp
index 413530a5ec..5f68e40467 100644
--- a/platform/android/src/style/sources/source.cpp
+++ b/platform/android/src/style/sources/source.cpp
@@ -51,7 +51,7 @@ namespace android {
if (!coreSource.peer.has_value()) {
coreSource.peer = createSourcePeer(env, coreSource, frontend);
}
- return *mbgl::util::any_cast<std::unique_ptr<Source>>(&coreSource.peer)->get()->javaPeer;
+ return *coreSource.peer.get<std::unique_ptr<Source>>()->javaPeer;
}
Source::Source(jni::JNIEnv& env, mbgl::style::Source& coreSource, jni::Object<Source> obj, AndroidRendererFrontend& frontend)
@@ -125,7 +125,7 @@ namespace android {
// Release the peer relationships. These will be re-established when the source is added to a map
assert(ownedSource->peer.has_value());
- util::any_cast<std::unique_ptr<Source>>(&(ownedSource->peer))->release();
+ ownedSource->peer.get<std::unique_ptr<Source>>().release();
ownedSource->peer.reset();
// Release the strong reference to the java peer
diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index 3f9bfbf8ca..e0415c02f7 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -177,7 +177,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
}
- (MGLSource *)sourceFromMBGLSource:(mbgl::style::Source *)rawSource {
- if (MGLSource *source = rawSource->peer.has_value() ? mbgl::util::any_cast<SourceWrapper>(rawSource->peer).source : nil) {
+ if (MGLSource *source = rawSource->peer.has_value() ? rawSource->peer.get<SourceWrapper>().source : nil) {
return source;
}
@@ -341,7 +341,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
{
NSParameterAssert(rawLayer);
- if (MGLStyleLayer *layer = rawLayer->peer.has_value() ? mbgl::util::any_cast<LayerWrapper>(&(rawLayer->peer))->layer : nil) {
+ if (MGLStyleLayer *layer = rawLayer->peer.has_value() ? rawLayer->peer.get<LayerWrapper>().layer : nil) {
return layer;
}
diff --git a/test/util/peer.test.cpp b/test/util/peer.test.cpp
new file mode 100644
index 0000000000..aa4dae5a88
--- /dev/null
+++ b/test/util/peer.test.cpp
@@ -0,0 +1,194 @@
+#include <mbgl/test/util.hpp>
+
+#include <mbgl/util/peer.hpp>
+
+using namespace mbgl::util;
+
+class TestType {
+public:
+ TestType() : i1(0), i2(1) {
+ str[0] = 'a';
+ }
+
+ //Detect moves
+ TestType(TestType&& t): i1(t.i1+1), i2(t.i2+2) {
+ str[0] = t.str[0]+1;
+ }
+
+ TestType(const TestType&) = delete;
+ TestType& operator=(const TestType&) = delete;
+
+ int i1;
+ int i2;
+ char str[256];
+};
+
+bool IsStackAllocated (const peer& a, const void* obj1) {
+ uintptr_t a_ptr = (uintptr_t)(&a);
+ uintptr_t obj = (uintptr_t)(obj1);
+ return (obj >= a_ptr && obj < a_ptr + sizeof(peer));
+};
+
+TEST(Peer, Empty) {
+ EXPECT_FALSE(peer().has_value());
+}
+
+TEST(Peer, BasicTypes) {
+ peer i = 3;
+ EXPECT_TRUE(i.has_value());
+ EXPECT_TRUE(i.get<decltype(3)>() == 3);
+
+ auto iValue = i.get<decltype(3)>();
+ EXPECT_TRUE(iValue == 3);
+
+ EXPECT_TRUE(peer(4).has_value());
+ EXPECT_TRUE(peer(4).get<decltype(4)>() == 4);
+
+ peer f = 6.2f;
+ EXPECT_TRUE(f.has_value());
+ EXPECT_TRUE(f.get<decltype(6.2f)>() == 6.2f);
+
+ const float fValue = f.get<decltype(6.2f)>();
+ EXPECT_TRUE(fValue == 6.2f);
+
+ EXPECT_TRUE(peer(1.0f).has_value());
+ EXPECT_TRUE(peer(1.0f).get<decltype(1.0f)>() == 1.0f);
+
+ peer c = 'z';
+ EXPECT_TRUE(c.has_value());
+ EXPECT_TRUE(c.get<decltype('z')>() == 'z');
+
+ EXPECT_TRUE(peer('z').has_value());
+ EXPECT_TRUE(peer('z').get<decltype('z')>() == 'z');
+}
+
+TEST(Peer, BasicTypes_Move) {
+ peer i = 3;
+ EXPECT_TRUE(i.has_value());
+
+ peer f = 6.2f;
+ EXPECT_TRUE(f.has_value());
+
+ f = std::move(i);
+ EXPECT_FALSE(i.has_value());
+
+ EXPECT_TRUE(f.has_value());
+ EXPECT_TRUE(f.get<decltype(3)>() == 3);
+}
+
+TEST(Peer, SmallType) {
+ struct T {
+ T(int32_t* p_) : p(p_) {
+ (*p)++;
+ }
+
+ T(T&& t) noexcept : p(t.p) {
+ (*p)++;
+ }
+
+ ~T() {
+ (*p)--;
+ }
+
+ T(const T&) = delete;
+ T& operator=(const T&) = delete;
+
+ int32_t* p;
+ };
+
+ int32_t p = 0;
+
+ {
+ peer u1 = peer(T(&p));
+ EXPECT_EQ(p, 1);
+
+ auto u2(std::move(u1));
+ EXPECT_EQ(p, 1);
+ }
+
+ EXPECT_EQ(p, 0);
+}
+
+// peer is not able to receive large types, unless we increase storage_t
+// capacity.
+//TEST(Peer, LargeType) {
+// TestType t1;
+// peer u1 = peer(std::move(t1));
+// EXPECT_TRUE(u1.has_value());
+//
+// //TestType should be moved into owning peer
+// EXPECT_EQ(u1.get<TestType>().i1, 1);
+//
+// auto u2(std::move(u1));
+// EXPECT_FALSE(u1.has_value());
+//
+// //TestType should not be moved when owning peer is moved;
+// EXPECT_EQ(u2.get<TestType>().i1, 1);
+//
+// //TestType should be moved out of owning peer
+// // Note: two moves are involved in returning the moved value
+// // First out of the peer, and then in the return statement
+// auto t2 = std::move(u2.get<TestType>());
+// EXPECT_FALSE(u2.has_value());
+// EXPECT_EQ(t2.i1, 3);
+//}
+
+TEST(Peer, Pointer) {
+ auto t1 = new TestType();
+
+ auto u1 = peer(std::move(t1));
+ EXPECT_TRUE(u1.has_value());
+
+ //Only the pointer should be moved
+ TestType * t2 = u1.get<TestType *>();
+ EXPECT_EQ(t2->i1, 0);
+
+ peer u2(4);
+ std::swap(u2, u1);
+
+ EXPECT_TRUE(u1.has_value());
+
+ EXPECT_TRUE(u2.has_value());
+
+ t2 = u2.get<TestType *>();
+ EXPECT_EQ(t2->i1, 0);
+ delete t2;
+}
+
+
+TEST(Peer, UniquePtr) {
+ auto t1 = std::make_unique<TestType>();
+ auto u1 = peer(std::move(t1));
+
+ EXPECT_EQ(t1.get(), nullptr);
+ EXPECT_TRUE(u1.has_value());
+
+ auto t2 = std::move(u1.take<TestType>());
+ EXPECT_FALSE(u1.has_value());
+ (void)t2;
+
+ peer u2;
+ TestType * t3 = new TestType();
+ u2 = std::unique_ptr<TestType>(t3);
+ EXPECT_TRUE(u2.has_value());
+}
+
+TEST(Peer, SharedPtr) {
+
+ std::shared_ptr<int> shared(new int(3));
+ std::weak_ptr<int> weak = shared;
+ peer u1 = 0;
+
+ EXPECT_EQ(weak.use_count(), 1);
+ peer u2 = shared;
+ EXPECT_EQ(weak.use_count(), 2);
+
+ u1 = std::move(u2);
+ EXPECT_EQ(weak.use_count(), 2);
+ u2.swap(u1);
+ EXPECT_EQ(weak.use_count(), 2);
+ u2 = 0;
+ EXPECT_EQ(weak.use_count(), 1);
+ shared = nullptr;
+ EXPECT_EQ(weak.use_count(), 0);
+}
diff --git a/test/util/unique_any.test.cpp b/test/util/unique_any.test.cpp
deleted file mode 100644
index 9b622cd284..0000000000
--- a/test/util/unique_any.test.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-#include <mbgl/test/util.hpp>
-
-#include <mbgl/util/unique_any.hpp>
-
-using namespace mbgl::util;
-
-class TestType {
-public:
- TestType() : i1(0), i2(1) {
- str[0] = 'a';
- }
-
- //Detect moves
- TestType(TestType&& t): i1(t.i1+1), i2(t.i2+2) {
- str[0] = t.str[0]+1;
- }
-
- TestType(const TestType&) = delete;
- TestType& operator=(const TestType&) = delete;
-
- int i1;
- int i2;
- char str[256];
-};
-
-bool IsStackAllocated (const unique_any& a, const void* obj1) {
- uintptr_t a_ptr = (uintptr_t)(&a);
- uintptr_t obj = (uintptr_t)(obj1);
- return (obj >= a_ptr && obj < a_ptr + sizeof(unique_any));
-};
-
-TEST(UniqueAny, Empty) {
- EXPECT_FALSE(unique_any().has_value());
- EXPECT_TRUE(unique_any().type() == typeid(void));
- EXPECT_THROW(any_cast<int>(unique_any()), bad_any_cast);
-}
-
-TEST(UniqueAny, BasicTypes) {
- unique_any i = 3;
- EXPECT_TRUE(i.has_value());
- EXPECT_TRUE(i.type() == typeid(int));
- EXPECT_TRUE(IsStackAllocated(i, any_cast<int>(&i)));
-
- auto iValue = any_cast<int>(i);
- EXPECT_TRUE(iValue == 3);
-
- EXPECT_TRUE(unique_any(4).has_value());
- EXPECT_TRUE(unique_any(4).type() == typeid(int));
-
- unique_any f = 6.2f;
- EXPECT_TRUE(f.has_value());
- EXPECT_TRUE(f.type() == typeid(float));
- EXPECT_TRUE(IsStackAllocated(f, any_cast<float>(&f)));
-
- const float fValue = any_cast<const float>(f);
- EXPECT_TRUE(fValue == 6.2f);
-
- EXPECT_TRUE(unique_any(1.0f).has_value());
- EXPECT_TRUE(unique_any(1.0f).type() == typeid(float));
-
- unique_any c = 'z';
- EXPECT_TRUE(c.has_value());
- EXPECT_TRUE(c.type() == typeid(char));
- EXPECT_TRUE(IsStackAllocated(c, any_cast<char>(&c)));
-
- EXPECT_THROW(any_cast<float>(c), bad_any_cast);
-
- EXPECT_TRUE(unique_any('4').has_value());
- EXPECT_TRUE(unique_any('4').type() == typeid(char));
-}
-
-TEST(UniqueAny, BasicTypes_Move) {
- unique_any i = 3;
- EXPECT_TRUE(i.has_value());
- EXPECT_TRUE(i.type() == typeid(int));
-
- unique_any f = 6.2f;
- EXPECT_TRUE(f.has_value());
- EXPECT_TRUE(f.type() == typeid(float));
-
- f = std::move(i);
- EXPECT_FALSE(i.has_value());
- EXPECT_TRUE(i.type() == typeid(void));
-
- EXPECT_TRUE(f.has_value());
- EXPECT_TRUE(f.type() == typeid(int));
-
-}
-
-TEST(UniqueAny, SmallType) {
- struct T {
- T(int32_t* p_) : p(p_) {
- (*p)++;
- }
-
- T(T&& t) noexcept : p(t.p) {
- (*p)++;
- }
-
- ~T() {
- (*p)--;
- }
-
- T(const T&) = delete;
- T& operator=(const T&) = delete;
-
- int32_t* p;
- };
-
- int32_t p = 0;
-
- {
- unique_any u1 = unique_any(T(&p));
- EXPECT_EQ(p, 1);
-
- auto u2(std::move(u1));
- EXPECT_EQ(p, 1);
- }
-
- EXPECT_EQ(p, 0);
-}
-
-TEST(UniqueAny, LargeType) {
- TestType t1;
- unique_any u1 = unique_any(std::move(t1));
- EXPECT_TRUE(u1.has_value());
- EXPECT_TRUE(u1.type() == typeid(TestType));
- EXPECT_FALSE(IsStackAllocated(u1, any_cast<TestType>(&u1)));
-
- //TestType should be moved into owning unique_any
- EXPECT_EQ(any_cast<TestType>(&u1)->i1, 1);
-
- auto u2(std::move(u1));
- EXPECT_TRUE(u2.type() == typeid(TestType));
- EXPECT_TRUE(u1.type() == typeid(void));
-
- //TestType should not be moved when owning unique_any is moved;
- EXPECT_EQ(any_cast<TestType>(&u2)->i1, 1);
-
- //TestType should be moved out of owning unique_any
- // Note: two moves are involved in returning the moved value
- // First out of the unique_any, and then in the return statement
- auto t2 = any_cast<TestType>(std::move(u2));
- EXPECT_EQ(t2.i1, 3);
- EXPECT_TRUE(u2.type() == typeid(void));
-}
-
-TEST(UniqueAny, Pointer) {
- auto t1 = new TestType();
-
- auto u1 = unique_any(std::move(t1));
- EXPECT_TRUE(u1.has_value());
- EXPECT_TRUE(u1.type() == typeid(TestType *));
- EXPECT_TRUE(IsStackAllocated(u1, any_cast<TestType *>(&u1)));
-
- //Only the pointer should be moved
- TestType * t2 = *any_cast<TestType *>(&u1);
- EXPECT_EQ(t2->i1, 0);
-
- unique_any u2(4);
- std::swap(u2, u1);
-
- EXPECT_TRUE(u1.has_value());
- EXPECT_TRUE(u1.type() == typeid(int));
-
- EXPECT_TRUE(u2.has_value());
- EXPECT_TRUE(u2.type() == typeid(TestType *));
-
- t2 = *any_cast<TestType *>(&u2);
- EXPECT_EQ(t2->i1, 0);
- delete t2;
-}
-
-
-TEST(UniqueAny, UniquePtr) {
- auto t1 = std::make_unique<TestType>();
- auto u1 = unique_any(std::move(t1));
-
- EXPECT_EQ(t1.get(), nullptr);
- EXPECT_TRUE(u1.has_value());
- EXPECT_TRUE(u1.type() == typeid(std::unique_ptr<TestType>));
-
- EXPECT_TRUE(IsStackAllocated(u1, any_cast<std::unique_ptr<TestType>>(&u1)));
-
- auto t2 = any_cast<std::unique_ptr<TestType> >(std::move(u1));
- EXPECT_FALSE(u1.has_value());
-
- unique_any u2;
- TestType * t3 = new TestType();
- u2 = std::unique_ptr<TestType>(t3);
- EXPECT_TRUE(u2.has_value());
- EXPECT_TRUE(any_cast<std::unique_ptr<TestType>>(&u2)->get() == t3);
-}
-
-TEST(UniqueAny, SharedPtr) {
-
- std::shared_ptr<int> shared(new int(3));
- std::weak_ptr<int> weak = shared;
- unique_any u1 = 0;
-
- EXPECT_THROW(any_cast<float>(u1), bad_any_cast);
-
- EXPECT_EQ(weak.use_count(), 1);
- unique_any u2 = shared;
- EXPECT_EQ(weak.use_count(), 2);
-
- EXPECT_EQ(any_cast<std::unique_ptr<int>>(&u1), nullptr);
- EXPECT_FALSE(IsStackAllocated(u1, any_cast<std::shared_ptr<TestType>>(&u1)));
-
- u1 = std::move(u2);
- EXPECT_EQ(weak.use_count(), 2);
- u2.swap(u1);
- EXPECT_EQ(weak.use_count(), 2);
- u2 = 0;
- EXPECT_EQ(weak.use_count(), 1);
- shared = nullptr;
- EXPECT_EQ(weak.use_count(), 0);
-}