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