Home | History | Annotate | Download | only in support
      1 #ifndef ANY_HELPERS_H
      2 #define ANY_HELPERS_H
      3 
      4 #include <experimental/any>
      5 #include <typeinfo>
      6 #include <type_traits>
      7 #include <cassert>
      8 
      9 #include "test_macros.h"
     10 
     11 #if !defined(TEST_HAS_NO_RTTI)
     12 #define RTTI_ASSERT(X) assert(X)
     13 #else
     14 #define RTTI_ASSERT(X)
     15 #endif
     16 
     17 template <class _Tp>
     18   struct IsSmallObject
     19     : public std::integral_constant<bool
     20         , sizeof(_Tp) <= (sizeof(void*)*3)
     21           && std::alignment_of<void*>::value
     22              % std::alignment_of<_Tp>::value == 0
     23           && std::is_nothrow_move_constructible<_Tp>::value
     24         >
     25   {};
     26 
     27 
     28 // Return 'true' if 'Type' will be considered a small type by 'any'
     29 template <class Type>
     30 bool isSmallType() {
     31 #if defined(_LIBCPP_VERSION)
     32     return std::experimental::__any_imp::_IsSmallObject<Type>::value;
     33 #else
     34     return IsSmallObject<Type>::value;
     35 #endif
     36 
     37 }
     38 
     39 // Assert that an object is empty. If the object used to contain an object
     40 // of type 'LastType' check that it can no longer be accessed.
     41 template <class LastType = int>
     42 void assertEmpty(std::experimental::any const& a) {
     43     assert(a.empty());
     44     RTTI_ASSERT(a.type() == typeid(void));
     45     assert(std::experimental::any_cast<LastType const>(&a) == nullptr);
     46 }
     47 
     48 // Assert that an 'any' object stores the specified 'Type' and 'value'.
     49 template <class Type>
     50 void assertContains(std::experimental::any const& a, int value = 1) {
     51     assert(!a.empty());
     52     RTTI_ASSERT(a.type() == typeid(Type));
     53     assert(std::experimental::any_cast<Type const &>(a).value == value);
     54 }
     55 
     56 // Modify the value of a "test type" stored within an any to the specified
     57 // 'value'.
     58 template <class Type>
     59 void modifyValue(std::experimental::any& a, int value) {
     60     assert(!a.empty());
     61     RTTI_ASSERT(a.type() == typeid(Type));
     62     std::experimental::any_cast<Type&>(a).value = value;
     63 }
     64 
     65 // A test type that will trigger the small object optimization within 'any'.
     66 template <int Dummy = 0>
     67 struct small_type
     68 {
     69     static int count;
     70     static int copied;
     71     static int moved;
     72     static int const_copied;
     73     static int non_const_copied;
     74 
     75     static void reset() {
     76         small_type::copied = 0;
     77         small_type::moved = 0;
     78         small_type::const_copied = 0;
     79         small_type::non_const_copied = 0;
     80     }
     81 
     82     int value;
     83 
     84     explicit small_type(int val) : value(val) {
     85         ++count;
     86     }
     87 
     88     small_type(small_type const & other) throw() {
     89         value = other.value;
     90         ++count;
     91         ++copied;
     92         ++const_copied;
     93     }
     94 
     95     small_type(small_type& other) throw() {
     96         value = other.value;
     97         ++count;
     98         ++copied;
     99         ++non_const_copied;
    100     }
    101 
    102     small_type(small_type && other) throw() {
    103         value = other.value;
    104         other.value = 0;
    105         ++count;
    106         ++moved;
    107     }
    108 
    109     ~small_type() {
    110         value = -1;
    111         --count;
    112     }
    113 
    114 private:
    115     small_type& operator=(small_type const&) = delete;
    116     small_type& operator=(small_type&&) = delete;
    117 };
    118 
    119 template <int Dummy>
    120 int small_type<Dummy>::count = 0;
    121 
    122 template <int Dummy>
    123 int small_type<Dummy>::copied = 0;
    124 
    125 template <int Dummy>
    126 int small_type<Dummy>::moved = 0;
    127 
    128 template <int Dummy>
    129 int small_type<Dummy>::const_copied = 0;
    130 
    131 template <int Dummy>
    132 int small_type<Dummy>::non_const_copied = 0;
    133 
    134 typedef small_type<> small;
    135 typedef small_type<1> small1;
    136 typedef small_type<2> small2;
    137 
    138 
    139 // A test type that will NOT trigger the small object optimization in any.
    140 template <int Dummy = 0>
    141 struct large_type
    142 {
    143     static int count;
    144     static int copied;
    145     static int moved;
    146     static int const_copied;
    147     static int non_const_copied;
    148 
    149     static void reset() {
    150         large_type::copied = 0;
    151         large_type::moved  = 0;
    152         large_type::const_copied = 0;
    153         large_type::non_const_copied = 0;
    154     }
    155 
    156     int value;
    157 
    158     large_type(int val) : value(val) {
    159         ++count;
    160         data[0] = 0;
    161     }
    162 
    163     large_type(large_type const & other) {
    164         value = other.value;
    165         ++count;
    166         ++copied;
    167         ++const_copied;
    168     }
    169 
    170     large_type(large_type & other) {
    171         value = other.value;
    172         ++count;
    173         ++copied;
    174         ++non_const_copied;
    175     }
    176 
    177     large_type(large_type && other) {
    178         value = other.value;
    179         other.value = 0;
    180         ++count;
    181         ++moved;
    182     }
    183 
    184     ~large_type()  {
    185         value = 0;
    186         --count;
    187     }
    188 
    189 private:
    190     large_type& operator=(large_type const&) = delete;
    191     large_type& operator=(large_type &&) = delete;
    192     int data[10];
    193 };
    194 
    195 template <int Dummy>
    196 int large_type<Dummy>::count = 0;
    197 
    198 template <int Dummy>
    199 int large_type<Dummy>::copied = 0;
    200 
    201 template <int Dummy>
    202 int large_type<Dummy>::moved = 0;
    203 
    204 template <int Dummy>
    205 int large_type<Dummy>::const_copied = 0;
    206 
    207 template <int Dummy>
    208 int large_type<Dummy>::non_const_copied = 0;
    209 
    210 typedef large_type<> large;
    211 typedef large_type<1> large1;
    212 typedef large_type<2> large2;
    213 
    214 // The exception type thrown by 'small_throws_on_copy', 'large_throws_on_copy'
    215 // and 'throws_on_move'.
    216 struct my_any_exception {};
    217 
    218 void throwMyAnyExpression() {
    219 #if !defined(TEST_HAS_NO_EXCEPTIONS)
    220         throw my_any_exception();
    221 #else
    222         assert(false && "Exceptions are disabled");
    223 #endif
    224 }
    225 
    226 // A test type that will trigger the small object optimization within 'any'.
    227 // this type throws if it is copied.
    228 struct small_throws_on_copy
    229 {
    230     static int count;
    231     int value;
    232 
    233     explicit small_throws_on_copy(int val = 0) : value(val) {
    234         ++count;
    235     }
    236 
    237     small_throws_on_copy(small_throws_on_copy const &) {
    238         throwMyAnyExpression();
    239     }
    240 
    241     small_throws_on_copy(small_throws_on_copy && other) throw() {
    242         value = other.value;
    243         ++count;
    244     }
    245 
    246     ~small_throws_on_copy() {
    247         --count;
    248     }
    249 private:
    250     small_throws_on_copy& operator=(small_throws_on_copy const&) = delete;
    251     small_throws_on_copy& operator=(small_throws_on_copy &&) = delete;
    252 };
    253 
    254 int small_throws_on_copy::count = 0;
    255 
    256 // A test type that will NOT trigger the small object optimization within 'any'.
    257 // this type throws if it is copied.
    258 struct large_throws_on_copy
    259 {
    260     static int count;
    261     int value = 0;
    262 
    263     explicit large_throws_on_copy(int val = 0) : value(val) {
    264         data[0] = 0;
    265         ++count;
    266     }
    267 
    268     large_throws_on_copy(large_throws_on_copy const &) {
    269          throwMyAnyExpression();
    270     }
    271 
    272     large_throws_on_copy(large_throws_on_copy && other) throw() {
    273         value = other.value;
    274         ++count;
    275     }
    276 
    277     ~large_throws_on_copy() {
    278         --count;
    279     }
    280 
    281 private:
    282     large_throws_on_copy& operator=(large_throws_on_copy const&) = delete;
    283     large_throws_on_copy& operator=(large_throws_on_copy &&) = delete;
    284     int data[10];
    285 };
    286 
    287 int large_throws_on_copy::count = 0;
    288 
    289 // A test type that throws when it is moved. This object will NOT trigger
    290 // the small object optimization in 'any'.
    291 struct throws_on_move
    292 {
    293     static int count;
    294     int value;
    295 
    296     explicit throws_on_move(int val = 0) : value(val) { ++count; }
    297 
    298     throws_on_move(throws_on_move const & other) {
    299         value = other.value;
    300         ++count;
    301     }
    302 
    303     throws_on_move(throws_on_move &&) {
    304         throwMyAnyExpression();
    305     }
    306 
    307     ~throws_on_move() {
    308         --count;
    309     }
    310 private:
    311     throws_on_move& operator=(throws_on_move const&) = delete;
    312     throws_on_move& operator=(throws_on_move &&) = delete;
    313 };
    314 
    315 int throws_on_move::count = 0;
    316 
    317 
    318 #endif
    319