stagefright/foundation: add copy and move constructor/assignment to AData

This was using default constructor/assignment that was not correct.

Bug: 79493409
Change-Id: I450db03cf762067e1e2ce7d0ef8a0bf6703d327d
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