blob: 49aa0dc44617d88b692a252486a2979402c38ae4 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef STAGEFRIGHT_FOUNDATION_A_DATA_H_
#define STAGEFRIGHT_FOUNDATION_A_DATA_H_
#include <memory> // for std::shared_ptr, weak_ptr and unique_ptr
#include <type_traits> // for std::aligned_union
#include <utils/StrongPointer.h> // for android::sp and wp
#include <media/stagefright/foundation/TypeTraits.h>
#include <media/stagefright/foundation/Flagged.h>
namespace android {
/**
* AData is a flexible union type that supports non-POD members. It supports arbitrary types as long
* as they are either moveable or copyable.
*
* Internally, AData is using AUnion - a structure providing the union support. AUnion should not
* be used by generic code as it is very unsafe - it opens type aliasing errors where an object of
* one type can be easily accessed as an object of another type. AData prevents this.
*
* AData allows a custom type flagger to be used for future extensions (e.g. allowing automatic
* type conversion). A strict and a relaxed flagger are provided as internal types.
*
* Use as follows:
*
* AData<int, float>::Basic data; // strict type support
* int i = 1;
* float f = 7.0f;
*
* data.set(5);
* EXPECT_TRUE(data.find(&i));
* EXPECT_FALSE(data.find(&f));
* EXPECT_EQ(i, 5);
*
* data.set(6.0f);
* EXPECT_FALSE(data.find(&i));
* EXPECT_TRUE(data.find(&f));
* EXPECT_EQ(f, 6.0f);
*
* AData<int, sp<RefBase>>::RelaxedBasic objdata; // relaxed type support
* sp<ABuffer> buf = new ABuffer(16), buf2;
* sp<RefBase> obj;
*
* objdata.set(buf);
* EXPECT_TRUE(objdata.find(&buf2));
* EXPECT_EQ(buf, buf2);
* EXPECT_FALSE(objdata.find(&i));
* EXPECT_TRUE(objdata.find(&obj));
* EXPECT_TRUE(obj == buf);
*
* obj = buf;
* objdata.set(obj); // storing as sp<RefBase>
* EXPECT_FALSE(objdata.find(&buf2)); // not stored as ABuffer(!)
* EXPECT_TRUE(objdata.find(&obj));
*/
/// \cond Internal
/**
* Helper class to call constructor and destructor for a specific type in AUnion.
* This class is needed as member function specialization is not allowed for a
* templated class.
*/
struct _AUnion_impl {
/**
* Calls placement constuctor for type T with arbitrary arguments for a storage at an address.
* Storage MUST be large enough to contain T.
* Also clears the slack space after type T. \todo This is not technically needed, so we may
* choose to do this just for debugging.
*
* \param totalSize size of the storage
* \param addr pointer to where object T should be constructed
* \param args arbitrary arguments for constructor
*/
template<typename T, typename ...Args>
inline static void emplace(size_t totalSize, T *addr, Args&&... args) {
new(addr)T(std::forward<Args>(args)...);
// clear slack space - this is not technically required
constexpr size_t size = sizeof(T);
memset(reinterpret_cast<uint8_t*>(addr) + size, 0, totalSize - size);
}
/**
* Calls destuctor for an object of type T located at a specific address.
*
* \note we do not clear the storage in this case as the storage should not be used
* until another object is placed there, at which case the storage will be cleared.
*
* \param addr pointer to where object T is stored
*/
template<typename T>
inline static void del(T *addr) {
addr->~T();
}
};
/** Constructor specialization for void type */
template<>
inline void _AUnion_impl::emplace<void>(size_t totalSize, void *addr) {
memset(addr, 0, totalSize);
}
/** Destructor specialization for void type */
template<>
inline void _AUnion_impl::del<void>(void *) {
}
/// \endcond
/**
* A templated union class that can contain specific types of data, and provides
* constructors, destructor and access methods strictly for those types.
*
* \note This class is VERY UNSAFE compared to a union, but it allows non-POD unions.
* In particular care must be taken that methods are called in a careful order to
* prevent accessing objects of one type as another type. This class provides no
* facilities to help with this ordering. This is meant to be wrapped by safer
* utility classes that do that.
*
* \param Ts types stored in this union.
*/
template<typename ...Ts>
struct AUnion {
private:
using _type = typename std::aligned_union<0, Ts...>::type; ///< storage type
_type mValue; ///< storage
public:
/**
* Constructs an object of type T with arbitrary arguments in this union. After this call,
* this union will contain this object.
*
* This method MUST be called only when either 1) no object or 2) a void object (equivalent to
* no object) is contained in this union.
*
* \param T type of object to be constructed. This must be one of the template parameters of
* the union class with the same cv-qualification, or void.
* \param args arbitrary arguments for the constructor
*/
template<
typename T, typename ...Args,
typename=typename std::enable_if<is_one_of<T, void, Ts...>::value>::type>
inline void emplace(Args&&... args) {
_AUnion_impl::emplace(
sizeof(_type), reinterpret_cast<T*>(&mValue), std::forward<Args>(args)...);
}
/**
* Destructs an object of type T in this union. After this call, this union will contain no
* object.
*
* This method MUST be called only when this union contains an object of type T.
*
* \param T type of object to be destructed. This must be one of the template parameters of
* the union class with the same cv-qualification, or void.
*/
template<
typename T,
typename=typename std::enable_if<is_one_of<T, void, Ts...>::value>::type>
inline void del() {
_AUnion_impl::del(reinterpret_cast<T*>(&mValue));
}
/**
* Returns a const reference to the object of type T in this union.
*
* This method MUST be called only when this union contains an object of type T.
*
* \param T type of object to be returned. This must be one of the template parameters of
* the union class with the same cv-qualification.
*/
template<
typename T,
typename=typename std::enable_if<is_one_of<T, Ts...>::value>::type>
inline const T &get() const {
return *reinterpret_cast<const T*>(&mValue);
}
/**
* Returns a reference to the object of type T in this union.
*
* This method MUST be called only when this union contains an object of type T.
*
* \param T type of object to be returned. This must be one of the template parameters of
* the union class with the same cv-qualification.
*/
template<typename T>
inline T &get() {
return *reinterpret_cast<T*>(&mValue);
}
};
/**
* Helper utility class that copies an object of type T to a destination.
*
* T must be copy assignable or copy constructible.
*
* It provides:
*
* void assign(T*, const U&) // for copiable types - this leaves the source unchanged, hence const.
*
* \param T type of object to assign to
*/
template<
typename T,
bool=std::is_copy_assignable<T>::value>
struct _AData_copier {
static_assert(std::is_copy_assignable<T>::value, "T must be copy assignable here");
/**
* Copies src to data without modifying data.
*
* \param data pointer to destination
* \param src source object
*/
inline static void assign(T *data, const T &src) {
*data = src;
}
template<typename U>
using enable_if_T_is_same_as = typename std::enable_if<std::is_same<U, T>::value>::type;
/**
* Downcast specializations for sp<>, shared_ptr<> and weak_ptr<>
*/
template<typename Tp, typename U, typename=enable_if_T_is_same_as<sp<Tp>>>
inline static void assign(sp<Tp> *data, const sp<U> &src) {
*data = static_cast<Tp*>(src.get());
}
template<typename Tp, typename U, typename=enable_if_T_is_same_as<wp<Tp>>>
inline static void assign(wp<Tp> *data, const wp<U> &src) {
sp<U> __tmp = src.promote();
*data = static_cast<Tp*>(__tmp.get());
}
template<typename Tp, typename U, typename=enable_if_T_is_same_as<sp<Tp>>>
inline static void assign(sp<Tp> *data, sp<U> &&src) {
sp<U> __tmp = std::move(src); // move src out as get cannot
*data = static_cast<Tp*>(__tmp.get());
}
template<typename Tp, typename U, typename=enable_if_T_is_same_as<std::shared_ptr<Tp>>>
inline static void assign(std::shared_ptr<Tp> *data, const std::shared_ptr<U> &src) {
*data = std::static_pointer_cast<Tp>(src);
}
template<typename Tp, typename U, typename=enable_if_T_is_same_as<std::shared_ptr<Tp>>>
inline static void assign(std::shared_ptr<Tp> *data, std::shared_ptr<U> &&src) {
std::shared_ptr<U> __tmp = std::move(src); // move src out as static_pointer_cast cannot
*data = std::static_pointer_cast<Tp>(__tmp);
}
template<typename Tp, typename U, typename=enable_if_T_is_same_as<std::weak_ptr<Tp>>>
inline static void assign(std::weak_ptr<Tp> *data, const std::weak_ptr<U> &src) {
*data = std::static_pointer_cast<Tp>(src.lock());
}
// shared_ptrs are implicitly convertible to weak_ptrs but not vice versa, but picking the
// first compatible type in Ts requires having shared_ptr types before weak_ptr types, so that
// they are stored as shared_ptrs.
/**
* Provide sensible error message if encountering shared_ptr/weak_ptr ambiguity. This method
* is not enough to detect this, only if someone is trying to find the shared_ptr.
*/
template<typename Tp, typename U>
inline static void assign(std::shared_ptr<Tp> *, const std::weak_ptr<U> &) {
static_assert(std::is_same<Tp, void>::value,
"shared/weak pointer ambiguity. move shared ptr types before weak_ptrs");
}
};
/**
* Template specialization for non copy assignable, but copy constructible types.
*
* \todo Test this. No basic classes are copy constructible but not assignable.
*
*/
template<typename T>
struct _AData_copier<T, false> {
static_assert(!std::is_copy_assignable<T>::value, "T must not be copy assignable here");
static_assert(std::is_copy_constructible<T>::value, "T must be copy constructible here");
inline static void copy(T *data, const T &src) {
data->~T();
new(data)T(src);
}
};
/**
* Helper utility class that moves an object of type T to a destination.
*
* T must be move assignable or move constructible.
*
* It provides multiple methods:
*
* void assign(T*, T&&)
*
* \param T type of object to assign
*/
template<
typename T,
bool=std::is_move_assignable<T>::value>
struct _AData_mover {
static_assert(std::is_move_assignable<T>::value, "T must be move assignable here");
/**
* Moves src to data while likely modifying it.
*
* \param data pointer to destination
* \param src source object
*/
inline static void assign(T *data, T &&src) {
*data = std::move(src);
}
template<typename U>
using enable_if_T_is_same_as = typename std::enable_if<std::is_same<U, T>::value>::type;
/**
* Downcast specializations for sp<>, shared_ptr<> and weak_ptr<>
*/
template<typename Tp, typename U, typename=enable_if_T_is_same_as<sp<Tp>>>
inline static void assign(sp<Tp> *data, sp<U> &&src) {
sp<U> __tmp = std::move(src); // move src out as get cannot
*data = static_cast<Tp*>(__tmp.get());
}
template<typename Tp, typename U, typename=enable_if_T_is_same_as<std::shared_ptr<Tp>>>
inline static void assign(std::shared_ptr<Tp> *data, std::shared_ptr<U> &&src) {
std::shared_ptr<U> __tmp = std::move(src); // move src out as static_pointer_cast cannot
*data = std::static_pointer_cast<Tp>(__tmp);
}
template<typename Tp, typename Td, typename U, typename Ud,
typename=enable_if_T_is_same_as<std::unique_ptr<Tp, Td>>>
inline static void assign(std::unique_ptr<Tp, Td> *data, std::unique_ptr<U, Ud> &&src) {
*data = std::unique_ptr<Tp, Td>(static_cast<Tp*>(src.release()));
}
// shared_ptrs are implicitly convertible to weak_ptrs but not vice versa, but picking the
// first compatible type in Ts requires having shared_ptr types before weak_ptr types, so that
// they are stored as shared_ptrs.
/**
* Provide sensible error message if encountering shared_ptr/weak_ptr ambiguity. This method
* is not enough to detect this, only if someone is trying to remove the shared_ptr.
*/
template<typename Tp, typename U>
inline static void assign(std::shared_ptr<Tp> *, std::weak_ptr<U> &&) {
static_assert(std::is_same<Tp, void>::value,
"shared/weak pointer ambiguity. move shared ptr types before weak_ptrs");
}
// unique_ptrs are implicitly convertible to shared_ptrs but not vice versa, but picking the
// first compatible type in Ts requires having unique_ptrs types before shared_ptrs types, so
// that they are stored as unique_ptrs.
/**
* Provide sensible error message if encountering shared_ptr/unique_ptr ambiguity. This method
* is not enough to detect this, only if someone is trying to remove the unique_ptr.
*/
template<typename Tp, typename U>
inline static void assign(std::unique_ptr<Tp> *, std::shared_ptr<U> &&) {
static_assert(std::is_same<Tp, void>::value,
"unique/shared pointer ambiguity. move unique ptr types before shared_ptrs");
}
};
/**
* Template specialization for non move assignable, but move constructible types.
*
* \todo Test this. No basic classes are move constructible but not assignable.
*
*/
template<typename T>
struct _AData_mover<T, false> {
static_assert(!std::is_move_assignable<T>::value, "T must not be move assignable here");
static_assert(std::is_move_constructible<T>::value, "T must be move constructible here");
inline static void assign(T *data, T &&src) {
data->~T();
new(data)T(std::move(src));
}
};
/**
* Helper template that deletes 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 deleted
* \param Ts types to consider for the member
*/
template<typename Flagger, typename U, typename ...Ts>
struct _AData_deleter;
/**
* Template specialization when there are still types to consider (T and rest)
*/
template<typename Flagger, typename U, typename T, typename ...Ts>
struct _AData_deleter<Flagger, U, T, Ts...> {
static bool del(typename Flagger::type flags, U &data) {
if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
data.template del<T>();
return true;
}
return _AData_deleter<Flagger, U, Ts...>::del(flags, data);
}
};
/**
* Template specialization when there are no more types to consider.
*/
template<typename Flagger, typename U>
struct _AData_deleter<Flagger, U> {
inline static bool del(typename Flagger::type, 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
* strictness. The following inner classes are supported:
*
* AData<types...>::Basic - strict type support using uint32_t flag.
*
* AData<types...>::Strict<Flag> - strict type support using custom flag.
* AData<types...>::Relaxed<Flag, MaxSize, Align>
* - relaxed type support with compatible (usually derived) class support
* for pointer types with added size checking for minimal additional
* safety.
*
* AData<types...>::RelaxedBasic - strict type support using uint32_t flag.
*
* AData<types...>::Custom<flagger> - custom type support (flaggers determine the supported types
* and the base type to use for each)
*
*/
template<typename ...Ts>
struct AData {
private:
static_assert(are_unique<Ts...>::value, "types must be unique");
static constexpr size_t num_types = sizeof...(Ts); ///< number of types to support
public:
/**
* Default (strict) type flagger provided.
*
* The default flagger simply returns the index of the type within Ts, or 0 for void.
*
* Type flaggers return a flag for a supported type.
*
* They must provide:
*
* - a flagFor(T*) method for supported types _and_ for T=void. T=void is used to mark that no
* object is stored in the container. For this, an arbitrary unique value may be returned.
* - a mask field that contains the flag mask.
* - a canDeleteAs(Flag, Flag) flag comparison method that checks if a type of a flag can be
* deleted as another type.
*
* \param Flag the underlying unsigned integral to use for the flags.
*/
template<typename Flag>
struct flagger {
private:
static_assert(std::is_unsigned<Flag>::value, "Flag must be unsigned");
static_assert(std::is_integral<Flag>::value, "Flag must be an integral type");
static constexpr Flag count = num_types + 1;
public:
typedef Flag type; ///< flag type
static constexpr Flag mask = _Flagged_helper::minMask<Flag>(count); ///< flag mask
/**
* Return the stored type for T. This is itself.
*/
template<typename T>
struct store {
typedef T as_type; ///< the base type that T is stored as
};
/**
* Constexpr method that returns if two flags are compatible for deletion.
*
* \param objectFlag flag for object to be deleted
* \param deleteFlag flag for type that object is to be deleted as
*/
static constexpr bool canDeleteAs(Flag objectFlag, Flag deleteFlag) {
// default flagger requires strict type equality
return objectFlag == deleteFlag;
}
/**
* Constexpr method that returns the flag to use for a given type.
*
* Function overload for void*.
*/
static constexpr Flag flagFor(void*) {
return 0u;
}
/**
* Constexpr method that returns the flag to use for a given supported type (T).
*/
template<typename T, typename=typename std::enable_if<is_one_of<T, Ts...>::value>::type>
static constexpr Flag flagFor(T*) {
return find_first<T, Ts...>::index;
}
};
/**
* Relaxed flagger returns the index of the type within Ts. However, for pointers T* it returns
* the first type in Ts that T* can be converted into (this is normally a base type, but also
* works for sp<>, shared_ptr<> or unique_ptr<>). For a bit more strictness, the flag also
* contains the size of the class to avoid finding objects that were stored as a different
* derived class of the same base class.
*
* Flag is basically the index of the (base) type in Ts multiplied by the max size stored plus
* the size of the type (divided by alignment) for derived pointer types.
*
* \param MaxSize max supported size for derived class pointers
* \param Align alignment to assume for derived class pointers
*/
template<typename Flag, size_t MaxSize=1024, size_t Align=4>
struct relaxed_flagger {
private:
static_assert(std::is_unsigned<Flag>::value, "Flag must be unsigned");
static_assert(std::is_integral<Flag>::value, "Flag must be an integral type");
static constexpr Flag count = num_types + 1;
static_assert(std::numeric_limits<Flag>::max() / count > (MaxSize / Align),
"not enough bits to fit into flag");
static constexpr Flag max_size_stored = MaxSize / Align + 1;
// T can be converted if it's size is <= MaxSize and it can be converted to one of the Ts
template<typename T, size_t size>
using enable_if_can_be_converted = typename std::enable_if<
(size / Align < max_size_stored
&& find_first_convertible_to<T, Ts...>::index)>::type;
template<typename W, typename T, typename=enable_if_can_be_converted<W, sizeof(T)>>
static constexpr Flag relaxedFlagFor(W*, T*) {
return find_first_convertible_to<W, Ts...>::index * max_size_stored
+ (is_one_of<W, Ts...>::value ? 0 : (sizeof(T) / Align));
}
public:
typedef Flag type; ///< flag type
static constexpr Flag mask =
_Flagged_helper::minMask<Flag>(count * max_size_stored); ///< flag mask
/**
* Constexpr method that returns if two flags are compatible for deletion.
*
* \param objectFlag flag for object to be deleted
* \param deleteFlag flag for type that object is to be deleted as
*/
static constexpr bool canDeleteAs(Flag objectFlag, Flag deleteFlag) {
// can delete if objects have the same base type
return
objectFlag / max_size_stored == deleteFlag / max_size_stored &&
(deleteFlag % max_size_stored) == 0;
}
/**
* Constexpr method that returns the flag to use for a given type.
*
* Function overload for void*.
*/
static constexpr Flag flagFor(void*) {
return 0u;
}
/**
* Constexpr method that returns the flag to use for a given supported type (T).
*
* This is a member method to enable both overloading as well as template specialization.
*/
template<typename T, typename=typename std::enable_if<is_one_of<T, Ts...>::value>::type>
static constexpr Flag flagFor(T*) {
return find_first<T, Ts...>::index * max_size_stored;
}
/**
* For precaution, we only consider converting pointers to their base classes.
*/
/**
* Template specialization for derived class pointers and managed pointers.
*/
template<typename T>
static constexpr Flag flagFor(T**p) { return relaxedFlagFor(p, (T*)0); }
template<typename T>
static constexpr Flag flagFor(std::shared_ptr<T>*p) { return relaxedFlagFor(p, (T*)0); }
template<typename T>
static constexpr Flag flagFor(std::unique_ptr<T>*p) { return relaxedFlagFor(p, (T*)0); }
template<typename T>
static constexpr Flag flagFor(std::weak_ptr<T>*p) { return relaxedFlagFor(p, (T*)0); }
template<typename T>
static constexpr Flag flagFor(sp<T>*p) { return relaxedFlagFor(p, (T*)0); }
template<typename T>
static constexpr Flag flagFor(wp<T>*p) { return relaxedFlagFor(p, (T*)0); }
/**
* Type support template that provodes the stored type for T.
* This is itself if it is one of Ts, or the first type in Ts that T is convertible to.
*
* NOTE: This template may provide a base class for an unsupported type. Support is
* determined by flagFor().
*/
template<typename T>
struct store {
typedef typename std::conditional<
is_one_of<T, Ts...>::value,
T,
typename find_first_convertible_to<T, Ts...>::type>::type as_type;
};
};
/**
* Implementation of AData.
*/
template<typename Flagger>
struct Custom : protected Flagged<AUnion<Ts...>, typename Flagger::type, Flagger::mask> {
using data_t = AUnion<Ts...>;
using base_t = Flagged<AUnion<Ts...>, typename Flagger::type, Flagger::mask>;
/**
* Constructor. Initializes this to a container that does not contain any object.
*/
Custom() : base_t(Flagger::flagFor((void*)0)) { }
/**
* Removes the contained object, if any.
*/
~Custom() {
if (!this->clear()) {
__builtin_trap();
// std::cerr << "could not delete data of type " << this->flags() << std::endl;
}
}
/**
* Returns whether there is any object contained.
*/
inline bool used() const {
return this->flags() != Flagger::flagFor((void*)0);
}
/**
* Removes the contained object, if any. Returns true if there are no objects contained,
* or false on any error (this is highly unexpected).
*/
bool clear() {
if (this->used()) {
if (_AData_deleter<Flagger, data_t, Ts...>::del(this->flags(), this->get())) {
this->setFlags(Flagger::flagFor((void*)0));
return true;
}
return false;
}
return true;
}
template<typename T>
using is_supported_by_flagger =
typename std::enable_if<Flagger::flagFor((T*)0) != Flagger::flagFor((void*)0)>::type;
/**
* Checks if there is a copiable object of type T in this container. If there is, it copies
* that object into the provided address and returns true. Otherwise, it does nothing and
* returns false.
*
* This method normally requires a flag equality between the stored and retrieved types.
* However, it also allows retrieving the stored object as the stored type
* (usually base type).
*
* \param T type of object to sought
* \param data address at which the object should be retrieved
*
* \return true if the object was retrieved. false if it was not.
*/
template<
typename T,
typename=is_supported_by_flagger<T>>
bool find(T *data) const {
using B = typename Flagger::template store<T>::as_type;
if (this->flags() == Flagger::flagFor((T*)0) ||
Flagger::canDeleteAs(this->flags(), Flagger::flagFor((T*)0))) {
_AData_copier<T>::assign(data, this->get().template get<B>());
return true;
}
return false;
}
/**
* Checks if there is an object of type T in this container. If there is, it moves that
* object into the provided address and returns true. Otherwise, it does nothing and returns
* false.
*
* This method normally requires a flag equality between the stored and retrieved types.
* However, it also allows retrieving the stored object as the stored type
* (usually base type).
*
* \param T type of object to sought
* \param data address at which the object should be retrieved.
*
* \return true if the object was retrieved. false if it was not.
*/
template<
typename T,
typename=is_supported_by_flagger<T>>
bool remove(T *data) {
using B = typename Flagger::template store<T>::as_type;
if (this->flags() == Flagger::flagFor((T*)0) ||
Flagger::canDeleteAs(this->flags(), Flagger::flagFor((T*)0))) {
_AData_mover<T>::assign(data, std::move(this->get().template get<B>()));
return true;
}
return false;
}
/**
* Stores an object into this container by copying. If it was successful, returns true.
* Otherwise, (e.g. it could not destroy the already stored object) it returns false. This
* latter would be highly unexpected.
*
* \param T type of object to store
* \param data object to store
*
* \return true if the object was stored. false if it was not.
*/
template<
typename T,
typename=is_supported_by_flagger<T>,
typename=typename std::enable_if<
std::is_copy_constructible<T>::value ||
(std::is_default_constructible<T>::value &&
std::is_copy_assignable<T>::value)>::type>
bool set(const T &data) {
using B = typename Flagger::template store<T>::as_type;
// if already contains an object of this type, simply assign
if (this->flags() == Flagger::flagFor((T*)0) && std::is_same<T, B>::value) {
_AData_copier<B>::assign(&this->get().template get<B>(), data);
return true;
} else if (this->used()) {
// destroy previous object
if (!this->clear()) {
return false;
}
}
this->get().template emplace<B>(data);
this->setFlags(Flagger::flagFor((T *)0));
return true;
}
/**
* Moves an object into this container. If it was successful, returns true. Otherwise,
* (e.g. it could not destroy the already stored object) it returns false. This latter
* would be highly unexpected.
*
* \param T type of object to store
* \param data object to store
*
* \return true if the object was stored. false if it was not.
*/
template<
typename T,
typename=is_supported_by_flagger<T>>
bool set(T &&data) {
using B = typename Flagger::template store<T>::as_type;
// if already contains an object of this type, simply assign
if (this->flags() == Flagger::flagFor((T*)0) && std::is_same<T, B>::value) {
_AData_mover<B>::assign(&this->get().template get<B>(), std::forward<T&&>(data));
return true;
} else if (this->used()) {
// destroy previous object
if (!this->clear()) {
return false;
}
}
this->get().template emplace<B>(std::forward<T&&>(data));
this->setFlags(Flagger::flagFor((T *)0));
return true;
}
};
/**
* Basic AData using the default type flagger and requested flag type.
*
* \param Flag desired flag type to use. Must be an unsigned and std::integral type.
*/
template<typename Flag>
using Strict = Custom<flagger<Flag>>;
/**
* Basic AData using the default type flagger and uint32_t flag.
*/
using Basic = Strict<uint32_t>;
/**
* AData using the relaxed type flagger for max size and requested flag type.
*
* \param Flag desired flag type to use. Must be an unsigned and std::integral type.
*/
template<typename Flag, size_t MaxSize = 1024, size_t Align = 4>
using Relaxed = Custom<relaxed_flagger<Flag, MaxSize, Align>>;
/**
* Basic AData using the relaxed type flagger and uint32_t flag.
*/
using RelaxedBasic = Relaxed<uint32_t>;
};
} // namespace android
#endif // STAGEFRIGHT_FOUNDATION_A_DATA_H_