Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f252dd8d authored by Lajos Molnar's avatar Lajos Molnar
Browse files

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
parent c7c32133
Loading
Loading
Loading
Loading
+143 −0
Original line number Diff line number Diff line
@@ -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.
 *
@@ -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.
         */
+59 −0
Original line number Diff line number Diff line
@@ -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