1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef STAGEFRIGHT_FOUNDATION_A_DATA_H_
18 #define STAGEFRIGHT_FOUNDATION_A_DATA_H_
19
20 #include <memory> // for std::shared_ptr, weak_ptr and unique_ptr
21 #include <type_traits> // for std::aligned_union
22
23 #include <utils/StrongPointer.h> // for android::sp and wp
24
25 #include <media/stagefright/foundation/TypeTraits.h>
26 #include <media/stagefright/foundation/Flagged.h>
27
28 #undef HIDE
29 #define HIDE __attribute__((visibility("hidden")))
30
31 // The internals of AUnion cause problems with CFI
32 #undef NO_CFI
33 #define NO_CFI __attribute__((no_sanitize("cfi")))
34
35 namespace android {
36
37 /**
38 * AData is a flexible union type that supports non-POD members. It supports arbitrary types as long
39 * as they are either moveable or copyable.
40 *
41 * Internally, AData is using AUnion - a structure providing the union support. AUnion should not
42 * be used by generic code as it is very unsafe - it opens type aliasing errors where an object of
43 * one type can be easily accessed as an object of another type. AData prevents this.
44 *
45 * AData allows a custom type flagger to be used for future extensions (e.g. allowing automatic
46 * type conversion). A strict and a relaxed flagger are provided as internal types.
47 *
48 * Use as follows:
49 *
50 * AData<int, float>::Basic data; // strict type support
51 * int i = 1;
52 * float f = 7.0f;
53 *
54 * data.set(5);
55 * EXPECT_TRUE(data.find(&i));
56 * EXPECT_FALSE(data.find(&f));
57 * EXPECT_EQ(i, 5);
58 *
59 * data.set(6.0f);
60 * EXPECT_FALSE(data.find(&i));
61 * EXPECT_TRUE(data.find(&f));
62 * EXPECT_EQ(f, 6.0f);
63 *
64 * AData<int, sp<RefBase>>::RelaxedBasic objdata; // relaxed type support
65 * sp<ABuffer> buf = new ABuffer(16), buf2;
66 * sp<RefBase> obj;
67 *
68 * objdata.set(buf);
69 * EXPECT_TRUE(objdata.find(&buf2));
70 * EXPECT_EQ(buf, buf2);
71 * EXPECT_FALSE(objdata.find(&i));
72 * EXPECT_TRUE(objdata.find(&obj));
73 * EXPECT_TRUE(obj == buf);
74 *
75 * obj = buf;
76 * objdata.set(obj); // storing as sp<RefBase>
77 * EXPECT_FALSE(objdata.find(&buf2)); // not stored as ABuffer(!)
78 * EXPECT_TRUE(objdata.find(&obj));
79 */
80
81 /// \cond Internal
82
83 /**
84 * Helper class to call constructor and destructor for a specific type in AUnion.
85 * This class is needed as member function specialization is not allowed for a
86 * templated class.
87 */
88 struct HIDE _AUnion_impl {
89 /**
90 * Calls placement constuctor for type T with arbitrary arguments for a storage at an address.
91 * Storage MUST be large enough to contain T.
92 * Also clears the slack space after type T. \todo This is not technically needed, so we may
93 * choose to do this just for debugging.
94 *
95 * \param totalSize size of the storage
96 * \param addr pointer to where object T should be constructed
97 * \param args arbitrary arguments for constructor
98 */
99 template<typename T, typename ...Args>
emplace_AUnion_impl100 inline static void NO_CFI emplace(size_t totalSize, T *addr, Args&&... args) {
101 new(addr)T(std::forward<Args>(args)...);
102 // clear slack space - this is not technically required
103 constexpr size_t size = sizeof(T);
104 memset(reinterpret_cast<uint8_t*>(addr) + size, 0, totalSize - size);
105 }
106
107 /**
108 * Calls destuctor for an object of type T located at a specific address.
109 *
110 * \note we do not clear the storage in this case as the storage should not be used
111 * until another object is placed there, at which case the storage will be cleared.
112 *
113 * \param addr pointer to where object T is stored
114 */
115 template<typename T>
del_AUnion_impl116 inline static void del(T *addr) {
117 addr->~T();
118 }
119 };
120
121 /** Constructor specialization for void type */
122 template<>
123 HIDE inline void _AUnion_impl::emplace<void>(size_t totalSize, void *addr) {
124 memset(addr, 0, totalSize);
125 }
126
127 /** Destructor specialization for void type */
128 template<>
del(void *)129 HIDE inline void _AUnion_impl::del<void>(void *) {
130 }
131
132 /// \endcond
133
134 /**
135 * A templated union class that can contain specific types of data, and provides
136 * constructors, destructor and access methods strictly for those types.
137 *
138 * \note This class is VERY UNSAFE compared to a union, but it allows non-POD unions.
139 * In particular care must be taken that methods are called in a careful order to
140 * prevent accessing objects of one type as another type. This class provides no
141 * facilities to help with this ordering. This is meant to be wrapped by safer
142 * utility classes that do that.
143 *
144 * \param Ts types stored in this union.
145 */
146 template<typename ...Ts>
147 struct AUnion {
148 private:
149 using _type = typename std::aligned_union<0, Ts...>::type; ///< storage type
150 _type mValue; ///< storage
151
152 public:
153 /**
154 * Constructs an object of type T with arbitrary arguments in this union. After this call,
155 * this union will contain this object.
156 *
157 * This method MUST be called only when either 1) no object or 2) a void object (equivalent to
158 * no object) is contained in this union.
159 *
160 * \param T type of object to be constructed. This must be one of the template parameters of
161 * the union class with the same cv-qualification, or void.
162 * \param args arbitrary arguments for the constructor
163 */
164 template<
165 typename T, typename ...Args,
166 typename=typename std::enable_if<is_one_of<T, void, Ts...>::value>::type>
emplaceAUnion167 inline void NO_CFI emplace(Args&&... args) {
168 _AUnion_impl::emplace(
169 sizeof(_type), reinterpret_cast<T*>(&mValue), std::forward<Args>(args)...);
170 }
171
172 /**
173 * Destructs an object of type T in this union. After this call, this union will contain no
174 * object.
175 *
176 * This method MUST be called only when this union contains an object of type T.
177 *
178 * \param T type of object to be destructed. This must be one of the template parameters of
179 * the union class with the same cv-qualification, or void.
180 */
181 template<
182 typename T,
183 typename=typename std::enable_if<is_one_of<T, void, Ts...>::value>::type>
delAUnion184 inline void del() {
185 _AUnion_impl::del(reinterpret_cast<T*>(&mValue));
186 }
187
188 /**
189 * Returns a const reference to the object of type T in this union.
190 *
191 * This method MUST be called only when this union contains an object of type T.
192 *
193 * \param T type of object to be returned. This must be one of the template parameters of
194 * the union class with the same cv-qualification.
195 */
196 template<
197 typename T,
198 typename=typename std::enable_if<is_one_of<T, Ts...>::value>::type>
getAUnion199 inline const T &get() const {
200 return *reinterpret_cast<const T*>(&mValue);
201 }
202
203 /**
204 * Returns a reference to the object of type T in this union.
205 *
206 * This method MUST be called only when this union contains an object of type T.
207 *
208 * \param T type of object to be returned. This must be one of the template parameters of
209 * the union class with the same cv-qualification.
210 */
211 template<typename T>
getAUnion212 inline T &get() {
213 return *reinterpret_cast<T*>(&mValue);
214 }
215 };
216
217 /**
218 * Helper utility class that copies an object of type T to a destination.
219 *
220 * T must be copy assignable or copy constructible.
221 *
222 * It provides:
223 *
224 * void assign(T*, const U&) // for copiable types - this leaves the source unchanged, hence const.
225 *
226 * \param T type of object to assign to
227 */
228 template<
229 typename T,
230 bool=std::is_copy_assignable<T>::value>
231 struct HIDE _AData_copier {
232 static_assert(std::is_copy_assignable<T>::value, "T must be copy assignable here");
233
234 /**
235 * Copies src to data without modifying data.
236 *
237 * \param data pointer to destination
238 * \param src source object
239 */
assign_AData_copier240 inline static void assign(T *data, const T &src) {
241 *data = src;
242 }
243
244 template<typename U>
245 using enable_if_T_is_same_as = typename std::enable_if<std::is_same<U, T>::value>::type;
246
247 /**
248 * Downcast specializations for sp<>, shared_ptr<> and weak_ptr<>
249 */
250 template<typename Tp, typename U, typename=enable_if_T_is_same_as<sp<Tp>>>
assign_AData_copier251 inline static void assign(sp<Tp> *data, const sp<U> &src) {
252 *data = static_cast<Tp*>(src.get());
253 }
254
255 template<typename Tp, typename U, typename=enable_if_T_is_same_as<wp<Tp>>>
assign_AData_copier256 inline static void assign(wp<Tp> *data, const wp<U> &src) {
257 sp<U> __tmp = src.promote();
258 *data = static_cast<Tp*>(__tmp.get());
259 }
260
261 template<typename Tp, typename U, typename=enable_if_T_is_same_as<sp<Tp>>>
assign_AData_copier262 inline static void assign(sp<Tp> *data, sp<U> &&src) {
263 sp<U> __tmp = std::move(src); // move src out as get cannot
264 *data = static_cast<Tp*>(__tmp.get());
265 }
266
267 template<typename Tp, typename U, typename=enable_if_T_is_same_as<std::shared_ptr<Tp>>>
assign_AData_copier268 inline static void assign(std::shared_ptr<Tp> *data, const std::shared_ptr<U> &src) {
269 *data = std::static_pointer_cast<Tp>(src);
270 }
271
272 template<typename Tp, typename U, typename=enable_if_T_is_same_as<std::shared_ptr<Tp>>>
assign_AData_copier273 inline static void assign(std::shared_ptr<Tp> *data, std::shared_ptr<U> &&src) {
274 std::shared_ptr<U> __tmp = std::move(src); // move src out as static_pointer_cast cannot
275 *data = std::static_pointer_cast<Tp>(__tmp);
276 }
277
278 template<typename Tp, typename U, typename=enable_if_T_is_same_as<std::weak_ptr<Tp>>>
assign_AData_copier279 inline static void assign(std::weak_ptr<Tp> *data, const std::weak_ptr<U> &src) {
280 *data = std::static_pointer_cast<Tp>(src.lock());
281 }
282
283 // shared_ptrs are implicitly convertible to weak_ptrs but not vice versa, but picking the
284 // first compatible type in Ts requires having shared_ptr types before weak_ptr types, so that
285 // they are stored as shared_ptrs.
286 /**
287 * Provide sensible error message if encountering shared_ptr/weak_ptr ambiguity. This method
288 * is not enough to detect this, only if someone is trying to find the shared_ptr.
289 */
290 template<typename Tp, typename U>
assign_AData_copier291 inline static void assign(std::shared_ptr<Tp> *, const std::weak_ptr<U> &) {
292 static_assert(std::is_same<Tp, void>::value,
293 "shared/weak pointer ambiguity. move shared ptr types before weak_ptrs");
294 }
295 };
296
297 /**
298 * Template specialization for non copy assignable, but copy constructible types.
299 *
300 * \todo Test this. No basic classes are copy constructible but not assignable.
301 *
302 */
303 template<typename T>
304 struct HIDE _AData_copier<T, false> {
305 static_assert(!std::is_copy_assignable<T>::value, "T must not be copy assignable here");
306 static_assert(std::is_copy_constructible<T>::value, "T must be copy constructible here");
307
308 inline static void copy(T *data, const T &src) {
309 data->~T();
310 new(data)T(src);
311 }
312 };
313
314 /**
315 * Helper utility class that moves an object of type T to a destination.
316 *
317 * T must be move assignable or move constructible.
318 *
319 * It provides multiple methods:
320 *
321 * void assign(T*, T&&)
322 *
323 * \param T type of object to assign
324 */
325 template<
326 typename T,
327 bool=std::is_move_assignable<T>::value>
328 struct HIDE _AData_mover {
329 static_assert(std::is_move_assignable<T>::value, "T must be move assignable here");
330
331 /**
332 * Moves src to data while likely modifying it.
333 *
334 * \param data pointer to destination
335 * \param src source object
336 */
337 inline static void assign(T *data, T &&src) {
338 *data = std::move(src);
339 }
340
341 template<typename U>
342 using enable_if_T_is_same_as = typename std::enable_if<std::is_same<U, T>::value>::type;
343
344 /**
345 * Downcast specializations for sp<>, shared_ptr<> and weak_ptr<>
346 */
347 template<typename Tp, typename U, typename=enable_if_T_is_same_as<sp<Tp>>>
348 inline static void assign(sp<Tp> *data, sp<U> &&src) {
349 sp<U> __tmp = std::move(src); // move src out as get cannot
350 *data = static_cast<Tp*>(__tmp.get());
351 }
352
353 template<typename Tp, typename U, typename=enable_if_T_is_same_as<std::shared_ptr<Tp>>>
354 inline static void assign(std::shared_ptr<Tp> *data, std::shared_ptr<U> &&src) {
355 std::shared_ptr<U> __tmp = std::move(src); // move src out as static_pointer_cast cannot
356 *data = std::static_pointer_cast<Tp>(__tmp);
357 }
358
359 template<typename Tp, typename Td, typename U, typename Ud,
360 typename=enable_if_T_is_same_as<std::unique_ptr<Tp, Td>>>
361 inline static void assign(std::unique_ptr<Tp, Td> *data, std::unique_ptr<U, Ud> &&src) {
362 *data = std::unique_ptr<Tp, Td>(static_cast<Tp*>(src.release()));
363 }
364
365 // shared_ptrs are implicitly convertible to weak_ptrs but not vice versa, but picking the
366 // first compatible type in Ts requires having shared_ptr types before weak_ptr types, so that
367 // they are stored as shared_ptrs.
368 /**
369 * Provide sensible error message if encountering shared_ptr/weak_ptr ambiguity. This method
370 * is not enough to detect this, only if someone is trying to remove the shared_ptr.
371 */
372 template<typename Tp, typename U>
373 inline static void assign(std::shared_ptr<Tp> *, std::weak_ptr<U> &&) {
374 static_assert(std::is_same<Tp, void>::value,
375 "shared/weak pointer ambiguity. move shared ptr types before weak_ptrs");
376 }
377
378 // unique_ptrs are implicitly convertible to shared_ptrs but not vice versa, but picking the
379 // first compatible type in Ts requires having unique_ptrs types before shared_ptrs types, so
380 // that they are stored as unique_ptrs.
381 /**
382 * Provide sensible error message if encountering shared_ptr/unique_ptr ambiguity. This method
383 * is not enough to detect this, only if someone is trying to remove the unique_ptr.
384 */
385 template<typename Tp, typename U>
386 inline static void assign(std::unique_ptr<Tp> *, std::shared_ptr<U> &&) {
387 static_assert(std::is_same<Tp, void>::value,
388 "unique/shared pointer ambiguity. move unique ptr types before shared_ptrs");
389 }
390 };
391
392 /**
393 * Template specialization for non move assignable, but move constructible types.
394 *
395 * \todo Test this. No basic classes are move constructible but not assignable.
396 *
397 */
398 template<typename T>
399 struct HIDE _AData_mover<T, false> {
400 static_assert(!std::is_move_assignable<T>::value, "T must not be move assignable here");
401 static_assert(std::is_move_constructible<T>::value, "T must be move constructible here");
402
403 inline static void assign(T *data, T &&src) {
404 data->~T();
405 new(data)T(std::move(src));
406 }
407 };
408
409 /**
410 * Helper template that deletes an object of a specific type (member) in an AUnion.
411 *
412 * \param Flagger type flagger class (see AData)
413 * \param U AUnion object in which the member should be deleted
414 * \param Ts types to consider for the member
415 */
416 template<typename Flagger, typename U, typename ...Ts>
417 struct HIDE _AData_deleter;
418
419 /**
420 * Template specialization when there are still types to consider (T and rest)
421 */
422 template<typename Flagger, typename U, typename T, typename ...Ts>
423 struct HIDE _AData_deleter<Flagger, U, T, Ts...> {
424 static bool del(typename Flagger::type flags, U &data) {
425 if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
426 data.template del<T>();
427 return true;
428 }
429 return _AData_deleter<Flagger, U, Ts...>::del(flags, data);
430 }
431 };
432
433 /**
434 * Template specialization when there are no more types to consider.
435 */
436 template<typename Flagger, typename U>
437 struct HIDE _AData_deleter<Flagger, U> {
438 inline static bool del(typename Flagger::type, U &) {
439 return false;
440 }
441 };
442
443 /**
444 * Helper template that copy assigns an object of a specific type (member) in an
445 * AUnion.
446 *
447 * \param Flagger type flagger class (see AData)
448 * \param U AUnion object in which the member should be copy assigned
449 * \param Ts types to consider for the member
450 */
451 template<typename Flagger, typename U, typename ...Ts>
452 struct HIDE _AData_copy_assigner;
453
454 /**
455 * Template specialization when there are still types to consider (T and rest)
456 */
457 template<typename Flagger, typename U, typename T, typename ...Ts>
458 struct HIDE _AData_copy_assigner<Flagger, U, T, Ts...> {
459 static bool assign(typename Flagger::type flags, U &dst, const U &src) {
460 static_assert(std::is_copy_constructible<T>::value, "T must be copy constructible");
461 // if we can delete as, we can also assign as
462 if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
463 dst.template emplace<T>(src.template get<T>());
464 return true;
465 }
466 return _AData_copy_assigner<Flagger, U, Ts...>::assign(flags, dst, src);
467 }
468 };
469
470 /**
471 * Template specialization when there are no more types to consider.
472 */
473 template<typename Flagger, typename U>
474 struct HIDE _AData_copy_assigner<Flagger, U> {
475 inline static bool assign(typename Flagger::type, U &, const U &) {
476 return false;
477 }
478 };
479
480 /**
481 * Helper template that move assigns an object of a specific type (member) in an
482 * AUnion.
483 *
484 * \param Flagger type flagger class (see AData)
485 * \param U AUnion object in which the member should be copy assigned
486 * \param Ts types to consider for the member
487 */
488 template<typename Flagger, typename U, typename ...Ts>
489 struct HIDE _AData_move_assigner;
490
491 /**
492 * Template specialization when there are still types to consider (T and rest)
493 */
494 template<typename Flagger, typename U, typename T, typename ...Ts>
495 struct HIDE _AData_move_assigner<Flagger, U, T, Ts...> {
496 template<typename V = T>
497 static typename std::enable_if<std::is_move_constructible<V>::value, bool>::type
498 assign(typename Flagger::type flags, U &dst, U &src) {
499 // if we can delete as, we can also assign as
500 if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
501 dst.template emplace<T>(std::move(src.template get<T>()));
502 return true;
503 }
504 return _AData_move_assigner<Flagger, U, Ts...>::assign(flags, dst, src);
505 }
506
507 // Fall back to copy construction if T is not move constructible
508 template<typename V = T>
509 static typename std::enable_if<!std::is_move_constructible<V>::value, bool>::type
510 assign(typename Flagger::type flags, U &dst, U &src) {
511 static_assert(std::is_copy_constructible<T>::value, "T must be copy constructible");
512 // if we can delete as, we can also assign as
513 if (Flagger::canDeleteAs(flags, Flagger::flagFor((T*)0))) {
514 dst.template emplace<T>(src.template get<T>());
515 return true;
516 }
517 return _AData_move_assigner<Flagger, U, Ts...>::assign(flags, dst, src);
518 }
519 };
520
521 /**
522 * Template specialization when there are no more types to consider.
523 */
524 template<typename Flagger, typename U>
525 struct HIDE _AData_move_assigner<Flagger, U> {
526 inline static bool assign(typename Flagger::type, U &, U &) {
527 return false;
528 }
529 };
530
531 /**
532 * Container that can store an arbitrary object of a set of specified types.
533 *
534 * This struct is an outer class that contains various inner classes based on desired type
535 * strictness. The following inner classes are supported:
536 *
537 * AData<types...>::Basic - strict type support using uint32_t flag.
538 *
539 * AData<types...>::Strict<Flag> - strict type support using custom flag.
540 * AData<types...>::Relaxed<Flag, MaxSize, Align>
541 * - relaxed type support with compatible (usually derived) class support
542 * for pointer types with added size checking for minimal additional
543 * safety.
544 *
545 * AData<types...>::RelaxedBasic - strict type support using uint32_t flag.
546 *
547 * AData<types...>::Custom<flagger> - custom type support (flaggers determine the supported types
548 * and the base type to use for each)
549 *
550 */
551 template<typename ...Ts>
552 struct AData {
553 private:
554 static_assert(are_unique<Ts...>::value, "types must be unique");
555
556 static constexpr size_t num_types = sizeof...(Ts); ///< number of types to support
557
558 public:
559 /**
560 * Default (strict) type flagger provided.
561 *
562 * The default flagger simply returns the index of the type within Ts, or 0 for void.
563 *
564 * Type flaggers return a flag for a supported type.
565 *
566 * They must provide:
567 *
568 * - a flagFor(T*) method for supported types _and_ for T=void. T=void is used to mark that no
569 * object is stored in the container. For this, an arbitrary unique value may be returned.
570 * - a mask field that contains the flag mask.
571 * - a canDeleteAs(Flag, Flag) flag comparison method that checks if a type of a flag can be
572 * deleted as another type.
573 *
574 * \param Flag the underlying unsigned integral to use for the flags.
575 */
576 template<typename Flag>
577 struct flagger {
578 private:
579 static_assert(std::is_unsigned<Flag>::value, "Flag must be unsigned");
580 static_assert(std::is_integral<Flag>::value, "Flag must be an integral type");
581
582 static constexpr Flag count = num_types + 1;
583
584 public:
585 typedef Flag type; ///< flag type
586
587 static constexpr Flag mask = _Flagged_helper::minMask<Flag>(count); ///< flag mask
588
589 /**
590 * Return the stored type for T. This is itself.
591 */
592 template<typename T>
593 struct store {
594 typedef T as_type; ///< the base type that T is stored as
595 };
596
597 /**
598 * Constexpr method that returns if two flags are compatible for deletion.
599 *
600 * \param objectFlag flag for object to be deleted
601 * \param deleteFlag flag for type that object is to be deleted as
602 */
603 static constexpr bool canDeleteAs(Flag objectFlag, Flag deleteFlag) {
604 // default flagger requires strict type equality
605 return objectFlag == deleteFlag;
606 }
607
608 /**
609 * Constexpr method that returns the flag to use for a given type.
610 *
611 * Function overload for void*.
612 */
613 static constexpr Flag flagFor(void*) {
614 return 0u;
615 }
616
617 /**
618 * Constexpr method that returns the flag to use for a given supported type (T).
619 */
620 template<typename T, typename=typename std::enable_if<is_one_of<T, Ts...>::value>::type>
621 static constexpr Flag flagFor(T*) {
622 return find_first<T, Ts...>::index;
623 }
624 };
625
626 /**
627 * Relaxed flagger returns the index of the type within Ts. However, for pointers T* it returns
628 * the first type in Ts that T* can be converted into (this is normally a base type, but also
629 * works for sp<>, shared_ptr<> or unique_ptr<>). For a bit more strictness, the flag also
630 * contains the size of the class to avoid finding objects that were stored as a different
631 * derived class of the same base class.
632 *
633 * Flag is basically the index of the (base) type in Ts multiplied by the max size stored plus
634 * the size of the type (divided by alignment) for derived pointer types.
635 *
636 * \param MaxSize max supported size for derived class pointers
637 * \param Align alignment to assume for derived class pointers
638 */
639 template<typename Flag, size_t MaxSize=1024, size_t Align=4>
640 struct relaxed_flagger {
641 private:
642 static_assert(std::is_unsigned<Flag>::value, "Flag must be unsigned");
643 static_assert(std::is_integral<Flag>::value, "Flag must be an integral type");
644
645 static constexpr Flag count = num_types + 1;
646 static_assert(std::numeric_limits<Flag>::max() / count > (MaxSize / Align),
647 "not enough bits to fit into flag");
648
649 static constexpr Flag max_size_stored = MaxSize / Align + 1;
650
651 // T can be converted if it's size is <= MaxSize and it can be converted to one of the Ts
652 template<typename T, size_t size>
653 using enable_if_can_be_converted = typename std::enable_if<
654 (size / Align < max_size_stored
655 && find_first_convertible_to<T, Ts...>::index)>::type;
656
657
658 template<typename W, typename T, typename=enable_if_can_be_converted<W, sizeof(T)>>
659 static constexpr Flag relaxedFlagFor(W*, T*) {
660 return find_first_convertible_to<W, Ts...>::index * max_size_stored
661 + (is_one_of<W, Ts...>::value ? 0 : (sizeof(T) / Align));
662 }
663
664 public:
665 typedef Flag type; ///< flag type
666
667 static constexpr Flag mask =
668 _Flagged_helper::minMask<Flag>(count * max_size_stored); ///< flag mask
669
670 /**
671 * Constexpr method that returns if two flags are compatible for deletion.
672 *
673 * \param objectFlag flag for object to be deleted
674 * \param deleteFlag flag for type that object is to be deleted as
675 */
676 static constexpr bool canDeleteAs(Flag objectFlag, Flag deleteFlag) {
677 // can delete if objects have the same base type
678 return
679 objectFlag / max_size_stored == deleteFlag / max_size_stored &&
680 (deleteFlag % max_size_stored) == 0;
681 }
682
683 /**
684 * Constexpr method that returns the flag to use for a given type.
685 *
686 * Function overload for void*.
687 */
688 static constexpr Flag flagFor(void*) {
689 return 0u;
690 }
691
692 /**
693 * Constexpr method that returns the flag to use for a given supported type (T).
694 *
695 * This is a member method to enable both overloading as well as template specialization.
696 */
697 template<typename T, typename=typename std::enable_if<is_one_of<T, Ts...>::value>::type>
698 static constexpr Flag flagFor(T*) {
699 return find_first<T, Ts...>::index * max_size_stored;
700 }
701
702 /**
703 * For precaution, we only consider converting pointers to their base classes.
704 */
705
706 /**
707 * Template specialization for derived class pointers and managed pointers.
708 */
709 template<typename T>
710 static constexpr Flag flagFor(T**p) { return relaxedFlagFor(p, (T*)0); }
711 template<typename T>
712 static constexpr Flag flagFor(std::shared_ptr<T>*p) { return relaxedFlagFor(p, (T*)0); }
713 template<typename T>
714 static constexpr Flag flagFor(std::unique_ptr<T>*p) { return relaxedFlagFor(p, (T*)0); }
715 template<typename T>
716 static constexpr Flag flagFor(std::weak_ptr<T>*p) { return relaxedFlagFor(p, (T*)0); }
717 template<typename T>
718 static constexpr Flag flagFor(sp<T>*p) { return relaxedFlagFor(p, (T*)0); }
719 template<typename T>
720 static constexpr Flag flagFor(wp<T>*p) { return relaxedFlagFor(p, (T*)0); }
721
722 /**
723 * Type support template that provodes the stored type for T.
724 * This is itself if it is one of Ts, or the first type in Ts that T is convertible to.
725 *
726 * NOTE: This template may provide a base class for an unsupported type. Support is
727 * determined by flagFor().
728 */
729 template<typename T>
730 struct store {
731 typedef typename std::conditional<
732 is_one_of<T, Ts...>::value,
733 T,
734 typename find_first_convertible_to<T, Ts...>::type>::type as_type;
735 };
736 };
737
738 /**
739 * Implementation of AData.
740 */
741 template<typename Flagger>
742 struct Custom : protected Flagged<AUnion<Ts...>, typename Flagger::type, Flagger::mask> {
743 using data_t = AUnion<Ts...>;
744 using base_t = Flagged<AUnion<Ts...>, typename Flagger::type, Flagger::mask>;
745
746 /**
747 * Constructor. Initializes this to a container that does not contain any object.
748 */
749 Custom() : base_t(Flagger::flagFor((void*)0)) { }
750
751 /**
752 * Copy assignment operator.
753 */
754 Custom& operator=(const Custom &o) {
755 if (&o != this) {
756 if (this->used() && !this->clear()) {
757 __builtin_trap();
758 }
759 if (o.used()) {
760 if (_AData_copy_assigner<Flagger, data_t, Ts...>::assign(
761 o.flags(), this->get(), o.get())) {
762 this->setFlags(o.flags());
763 } else {
764 __builtin_trap();
765 }
766 }
767 }
768 return *this;
769 }
770
771 /**
772 * Copy constructor.
773 */
774 Custom(const Custom &o) : Custom() {
775 *this = o;
776 }
777
778 /**
779 * Move assignment operator.
780 */
781 Custom& operator=(Custom &&o) noexcept {
782 if (&o != this) {
783 if (this->used() && !this->clear()) {
784 __builtin_trap();
785 }
786 if (o.used()) {
787 if (_AData_move_assigner<Flagger, data_t, Ts...>::assign(
788 o.flags(), this->get(), o.get())) {
789 this->setFlags(o.flags());
790 o.clear();
791 } else {
792 __builtin_trap();
793 }
794 }
795 }
796 return *this;
797 }
798
799 /**
800 * Move constructor.
801 */
802 Custom(Custom &&o) noexcept : Custom() {
803 *this = std::move(o);
804 }
805
806 /**
807 * Removes the contained object, if any.
808 */
809 ~Custom() {
810 if (!this->clear()) {
811 __builtin_trap();
812 // std::cerr << "could not delete data of type " << this->flags() << std::endl;
813 }
814 }
815
816 /**
817 * Returns whether there is any object contained.
818 */
819 inline bool used() const {
820 return this->flags() != Flagger::flagFor((void*)0);
821 }
822
823 /**
824 * Removes the contained object, if any. Returns true if there are no objects contained,
825 * or false on any error (this is highly unexpected).
826 */
827 bool clear() {
828 if (this->used()) {
829 if (_AData_deleter<Flagger, data_t, Ts...>::del(this->flags(), this->get())) {
830 this->setFlags(Flagger::flagFor((void*)0));
831 return true;
832 }
833 return false;
834 }
835 return true;
836 }
837
838 template<typename T>
839 using is_supported_by_flagger =
840 typename std::enable_if<Flagger::flagFor((T*)0) != Flagger::flagFor((void*)0)>::type;
841
842 /**
843 * Checks if there is a copiable object of type T in this container. If there is, it copies
844 * that object into the provided address and returns true. Otherwise, it does nothing and
845 * returns false.
846 *
847 * This method normally requires a flag equality between the stored and retrieved types.
848 * However, it also allows retrieving the stored object as the stored type
849 * (usually base type).
850 *
851 * \param T type of object to sought
852 * \param data address at which the object should be retrieved
853 *
854 * \return true if the object was retrieved. false if it was not.
855 */
856 template<
857 typename T,
858 typename=is_supported_by_flagger<T>>
859 bool find(T *data) const {
860 using B = typename Flagger::template store<T>::as_type;
861 if (this->flags() == Flagger::flagFor((T*)0) ||
862 Flagger::canDeleteAs(this->flags(), Flagger::flagFor((T*)0))) {
863 _AData_copier<T>::assign(data, this->get().template get<B>());
864 return true;
865 }
866 return false;
867 }
868
869 /**
870 * Checks if there is an object of type T in this container. If there is, it moves that
871 * object into the provided address and returns true. Otherwise, it does nothing and returns
872 * false.
873 *
874 * This method normally requires a flag equality between the stored and retrieved types.
875 * However, it also allows retrieving the stored object as the stored type
876 * (usually base type).
877 *
878 * \param T type of object to sought
879 * \param data address at which the object should be retrieved.
880 *
881 * \return true if the object was retrieved. false if it was not.
882 */
883 template<
884 typename T,
885 typename=is_supported_by_flagger<T>>
886 bool remove(T *data) {
887 using B = typename Flagger::template store<T>::as_type;
888 if (this->flags() == Flagger::flagFor((T*)0) ||
889 Flagger::canDeleteAs(this->flags(), Flagger::flagFor((T*)0))) {
890 _AData_mover<T>::assign(data, std::move(this->get().template get<B>()));
891 return true;
892 }
893 return false;
894 }
895
896 /**
897 * Stores an object into this container by copying. If it was successful, returns true.
898 * Otherwise, (e.g. it could not destroy the already stored object) it returns false. This
899 * latter would be highly unexpected.
900 *
901 * \param T type of object to store
902 * \param data object to store
903 *
904 * \return true if the object was stored. false if it was not.
905 */
906 template<
907 typename T,
908 typename=is_supported_by_flagger<T>,
909 typename=typename std::enable_if<
910 std::is_copy_constructible<T>::value ||
911 (std::is_default_constructible<T>::value &&
912 std::is_copy_assignable<T>::value)>::type>
913 bool set(const T &data) {
914 using B = typename Flagger::template store<T>::as_type;
915
916 // if already contains an object of this type, simply assign
917 if (this->flags() == Flagger::flagFor((T*)0) && std::is_same<T, B>::value) {
918 _AData_copier<B>::assign(&this->get().template get<B>(), data);
919 return true;
920 } else if (this->used()) {
921 // destroy previous object
922 if (!this->clear()) {
923 return false;
924 }
925 }
926 this->get().template emplace<B>(data);
927 this->setFlags(Flagger::flagFor((T *)0));
928 return true;
929 }
930
931 /**
932 * Moves an object into this container. If it was successful, returns true. Otherwise,
933 * (e.g. it could not destroy the already stored object) it returns false. This latter
934 * would be highly unexpected.
935 *
936 * \param T type of object to store
937 * \param data object to store
938 *
939 * \return true if the object was stored. false if it was not.
940 */
941 template<
942 typename T,
943 typename=is_supported_by_flagger<T>>
944 bool set(T &&data) {
945 using B = typename Flagger::template store<T>::as_type;
946
947 // if already contains an object of this type, simply assign
948 if (this->flags() == Flagger::flagFor((T*)0) && std::is_same<T, B>::value) {
949 _AData_mover<B>::assign(&this->get().template get<B>(), std::forward<T&&>(data));
950 return true;
951 } else if (this->used()) {
952 // destroy previous object
953 if (!this->clear()) {
954 return false;
955 }
956 }
957 this->get().template emplace<B>(std::forward<T&&>(data));
958 this->setFlags(Flagger::flagFor((T *)0));
959 return true;
960 }
961 };
962
963 /**
964 * Basic AData using the default type flagger and requested flag type.
965 *
966 * \param Flag desired flag type to use. Must be an unsigned and std::integral type.
967 */
968 template<typename Flag>
969 using Strict = Custom<flagger<Flag>>;
970
971 /**
972 * Basic AData using the default type flagger and uint32_t flag.
973 */
974 using Basic = Strict<uint32_t>;
975
976 /**
977 * AData using the relaxed type flagger for max size and requested flag type.
978 *
979 * \param Flag desired flag type to use. Must be an unsigned and std::integral type.
980 */
981 template<typename Flag, size_t MaxSize = 1024, size_t Align = 4>
982 using Relaxed = Custom<relaxed_flagger<Flag, MaxSize, Align>>;
983
984 /**
985 * Basic AData using the relaxed type flagger and uint32_t flag.
986 */
987 using RelaxedBasic = Relaxed<uint32_t>;
988 };
989
990 } // namespace android
991
992 #endif // STAGEFRIGHT_FOUNDATION_A_DATA_H_
993
994