Merge "stagefright/foundation: clear type in AMessage::freeItemValue" into pi-dev
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
index 5acc6d6..85e4378 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
@@ -437,6 +437,94 @@
};
/**
+ * Helper template that copy assigns an object of a specific type (member) in an
+ * AUnion.
+ *
+ * \param Flagger type flagger class (see AData)
+ * \param U AUnion object in which the member should be copy assigned
+ * \param Ts types to consider for the member
+ */
+template<typename Flagger, typename U, typename ...Ts>
+struct HIDE _AData_copy_assigner;
+
+/**
+ * Template specialization when there are still types to consider (T and rest)
+ */
+template<typename Flagger, typename U, typename T, typename ...Ts>
+struct HIDE _AData_copy_assigner<Flagger, U, T, Ts...> {
+ static bool assign(typename Flagger::type flags, U &dst, const U &src) {
+ static_assert(std::is_copy_constructible<T>::value, "T must be copy constructible");
+ // if we can delete as, we can also assign as
+ if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
+ dst.template emplace<T>(src.template get<T>());
+ return true;
+ }
+ return _AData_copy_assigner<Flagger, U, Ts...>::assign(flags, dst, src);
+ }
+};
+
+/**
+ * Template specialization when there are no more types to consider.
+ */
+template<typename Flagger, typename U>
+struct HIDE _AData_copy_assigner<Flagger, U> {
+ inline static bool assign(typename Flagger::type, U &, const U &) {
+ return false;
+ }
+};
+
+/**
+ * Helper template that move assigns an object of a specific type (member) in an
+ * AUnion.
+ *
+ * \param Flagger type flagger class (see AData)
+ * \param U AUnion object in which the member should be copy assigned
+ * \param Ts types to consider for the member
+ */
+template<typename Flagger, typename U, typename ...Ts>
+struct HIDE _AData_move_assigner;
+
+/**
+ * Template specialization when there are still types to consider (T and rest)
+ */
+template<typename Flagger, typename U, typename T, typename ...Ts>
+struct HIDE _AData_move_assigner<Flagger, U, T, Ts...> {
+ template<typename V = T>
+ static typename std::enable_if<std::is_move_constructible<V>::value, bool>::type
+ assign(typename Flagger::type flags, U &dst, U &src) {
+ // if we can delete as, we can also assign as
+ if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
+ dst.template emplace<T>(std::move(src.template get<T>()));
+ return true;
+ }
+ return _AData_move_assigner<Flagger, U, Ts...>::assign(flags, dst, src);
+ }
+
+ // Fall back to copy construction if T is not move constructible
+ template<typename V = T>
+ static typename std::enable_if<!std::is_move_constructible<V>::value, bool>::type
+ assign(typename Flagger::type flags, U &dst, U &src) {
+ static_assert(std::is_copy_constructible<T>::value, "T must be copy constructible");
+ // if we can delete as, we can also assign as
+ if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
+ dst.template emplace<T>(src.template get<T>());
+ return true;
+ }
+ return _AData_move_assigner<Flagger, U, Ts...>::assign(flags, dst, src);
+ }
+};
+
+/**
+ * Template specialization when there are no more types to consider.
+ */
+template<typename Flagger, typename U>
+struct HIDE _AData_move_assigner<Flagger, U> {
+ inline static bool assign(typename Flagger::type, U &, U &) {
+ return false;
+ }
+};
+
+/**
* Container that can store an arbitrary object of a set of specified types.
*
* This struct is an outer class that contains various inner classes based on desired type
@@ -657,6 +745,61 @@
Custom() : base_t(Flagger::flagFor((void*)0)) { }
/**
+ * Copy assignment operator.
+ */
+ Custom& operator=(const Custom &o) {
+ if (&o != this) {
+ if (this->used() && !this->clear()) {
+ __builtin_trap();
+ }
+ if (o.used()) {
+ if (_AData_copy_assigner<Flagger, data_t, Ts...>::assign(
+ o.flags(), this->get(), o.get())) {
+ this->setFlags(o.flags());
+ } else {
+ __builtin_trap();
+ }
+ }
+ }
+ return *this;
+ }
+
+ /**
+ * Copy constructor.
+ */
+ Custom(const Custom &o) : Custom() {
+ *this = o;
+ }
+
+ /**
+ * Move assignment operator.
+ */
+ Custom& operator=(Custom &&o) {
+ if (&o != this) {
+ if (this->used() && !this->clear()) {
+ __builtin_trap();
+ }
+ if (o.used()) {
+ if (_AData_move_assigner<Flagger, data_t, Ts...>::assign(
+ o.flags(), this->get(), o.get())) {
+ this->setFlags(o.flags());
+ o.clear();
+ } else {
+ __builtin_trap();
+ }
+ }
+ }
+ return *this;
+ }
+
+ /**
+ * Move constructor.
+ */
+ Custom(Custom &&o) : Custom() {
+ *this = std::move(o);
+ }
+
+ /**
* Removes the contained object, if any.
*/
~Custom() {
diff --git a/media/libstagefright/foundation/tests/AData_test.cpp b/media/libstagefright/foundation/tests/AData_test.cpp
index f014c25..2628a47 100644
--- a/media/libstagefright/foundation/tests/AData_test.cpp
+++ b/media/libstagefright/foundation/tests/AData_test.cpp
@@ -978,4 +978,63 @@
}
};
+TEST_F(ADataTest, AData_AssignmentTest) {
+ typedef AData<sp<ABuffer>, int32_t>::Basic Data;
+
+ sp<ABuffer> buf1 = new ABuffer((void *)"hello", 6);
+ wp<ABuffer> buf1w = buf1;
+
+ Data obj1;
+ obj1.set(buf1);
+ EXPECT_NE(buf1w.promote(), nullptr);
+ buf1.clear();
+ EXPECT_NE(buf1w.promote(), nullptr);
+ obj1.clear();
+ EXPECT_EQ(buf1w.promote(), nullptr);
+
+ buf1 = new ABuffer((void *)"again", 6);
+ buf1w = buf1;
+
+ obj1.set(buf1);
+ EXPECT_TRUE(obj1.used());
+ Data obj2 = obj1;
+
+ sp<ABuffer> buf2;
+ EXPECT_TRUE(obj2.find(&buf2));
+ EXPECT_EQ(buf2, buf1);
+ buf1.clear();
+ buf2.clear();
+ EXPECT_NE(buf1w.promote(), nullptr);
+ obj1.clear();
+ EXPECT_NE(buf1w.promote(), nullptr);
+ obj2.clear();
+ EXPECT_EQ(buf1w.promote(), nullptr);
+
+ buf1 = new ABuffer((void *)"still", 6);
+ buf1w = buf1;
+
+ obj1.set(buf1);
+ EXPECT_TRUE(obj1.used());
+ obj2 = std::move(obj1);
+ EXPECT_FALSE(obj1.used());
+
+ EXPECT_TRUE(obj2.find(&buf2));
+ EXPECT_EQ(buf2, buf1);
+ buf1.clear();
+ buf2.clear();
+ EXPECT_NE(buf1w.promote(), nullptr);
+ obj2.clear();
+ EXPECT_EQ(buf1w.promote(), nullptr);
+
+ typedef AData<sp<ABuffer>, std::unique_ptr<int32_t>>::Basic Data2;
+ Data2 obj3, obj4;
+
+ buf1 = new ABuffer((void *)"hence", 6);
+ obj3.set(buf1);
+ obj4 = std::move(obj3);
+ EXPECT_FALSE(obj3.used());
+ EXPECT_TRUE(obj4.find(&buf2));
+ EXPECT_EQ(buf2, buf1);
+}
+
} // namespace android