Loading media/libstagefright/foundation/include/media/stagefright/foundation/AData.h +143 −0 Original line number Diff line number Diff line Loading @@ -436,6 +436,94 @@ struct HIDE _AData_deleter<Flagger, U> { } }; /** * 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. * Loading Loading @@ -656,6 +744,61 @@ public: */ 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. */ Loading media/libstagefright/foundation/tests/AData_test.cpp +59 −0 Original line number Diff line number Diff line Loading @@ -978,4 +978,63 @@ TEST_F(ADataTest, AData_RelaxedAndroidSpTest) { } }; 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 Loading
media/libstagefright/foundation/include/media/stagefright/foundation/AData.h +143 −0 Original line number Diff line number Diff line Loading @@ -436,6 +436,94 @@ struct HIDE _AData_deleter<Flagger, U> { } }; /** * 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. * Loading Loading @@ -656,6 +744,61 @@ public: */ 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. */ Loading
media/libstagefright/foundation/tests/AData_test.cpp +59 −0 Original line number Diff line number Diff line Loading @@ -978,4 +978,63 @@ TEST_F(ADataTest, AData_RelaxedAndroidSpTest) { } }; 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