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 _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST
     59 void assertContains(std::experimental::any const& a, int value = 1) {
     60     assert(!a.empty());
     61     RTTI_ASSERT(a.type() == typeid(Type));
     62     assert(std::experimental::any_cast<Type const &>(a).value == value);
     63 }
     64 
     65 // Modify the value of a "test type" stored within an any to the specified
     66 // 'value'.
     67 template <class Type>
     68 _LIBCPP_AVAILABILITY_THROW_BAD_ANY_CAST
     69 void modifyValue(std::experimental::any& a, int value) {
     70     assert(!a.empty());
     71     RTTI_ASSERT(a.type() == typeid(Type));
     72     std::experimental::any_cast<Type&>(a).value = value;
     73 }
     74 
     75 // A test type that will trigger the small object optimization within 'any'.
     76 template <int Dummy = 0>
     77 struct small_type
     78 {
     79     static int count;
     80     static int copied;
     81     static int moved;
     82     static int const_copied;
     83     static int non_const_copied;
     84 
     85     static void reset() {
     86         small_type::copied = 0;
     87         small_type::moved = 0;
     88         small_type::const_copied = 0;
     89         small_type::non_const_copied = 0;
     90     }
     91 
     92     int value;
     93 
     94     explicit small_type(int val) : value(val) {
     95         ++count;
     96     }
     97 
     98     small_type(small_type const & other) throw() {
     99         value = other.value;
    100         ++count;
    101         ++copied;
    102         ++const_copied;
    103     }
    104 
    105     small_type(small_type& other) throw() {
    106         value = other.value;
    107         ++count;
    108         ++copied;
    109         ++non_const_copied;
    110     }
    111 
    112     small_type(small_type && other) throw() {
    113         value = other.value;
    114         other.value = 0;
    115         ++count;
    116         ++moved;
    117     }
    118 
    119     ~small_type() {
    120         value = -1;
    121         --count;
    122     }
    123 
    124 private:
    125     small_type& operator=(small_type const&) = delete;
    126     small_type& operator=(small_type&&) = delete;
    127 };
    128 
    129 template <int Dummy>
    130 int small_type<Dummy>::count = 0;
    131 
    132 template <int Dummy>
    133 int small_type<Dummy>::copied = 0;
    134 
    135 template <int Dummy>
    136 int small_type<Dummy>::moved = 0;
    137 
    138 template <int Dummy>
    139 int small_type<Dummy>::const_copied = 0;
    140 
    141 template <int Dummy>
    142 int small_type<Dummy>::non_const_copied = 0;
    143 
    144 typedef small_type<> small;
    145 typedef small_type<1> small1;
    146 typedef small_type<2> small2;
    147 
    148 
    149 // A test type that will NOT trigger the small object optimization in any.
    150 template <int Dummy = 0>
    151 struct large_type
    152 {
    153     static int count;
    154     static int copied;
    155     static int moved;
    156     static int const_copied;
    157     static int non_const_copied;
    158 
    159     static void reset() {
    160         large_type::copied = 0;
    161         large_type::moved  = 0;
    162         large_type::const_copied = 0;
    163         large_type::non_const_copied = 0;
    164     }
    165 
    166     int value;
    167 
    168     large_type(int val) : value(val) {
    169         ++count;
    170         data[0] = 0;
    171     }
    172 
    173     large_type(large_type const & other) {
    174         value = other.value;
    175         ++count;
    176         ++copied;
    177         ++const_copied;
    178     }
    179 
    180     large_type(large_type & other) {
    181         value = other.value;
    182         ++count;
    183         ++copied;
    184         ++non_const_copied;
    185     }
    186 
    187     large_type(large_type && other) {
    188         value = other.value;
    189         other.value = 0;
    190         ++count;
    191         ++moved;
    192     }
    193 
    194     ~large_type()  {
    195         value = 0;
    196         --count;
    197     }
    198 
    199 private:
    200     large_type& operator=(large_type const&) = delete;
    201     large_type& operator=(large_type &&) = delete;
    202     int data[10];
    203 };
    204 
    205 template <int Dummy>
    206 int large_type<Dummy>::count = 0;
    207 
    208 template <int Dummy>
    209 int large_type<Dummy>::copied = 0;
    210 
    211 template <int Dummy>
    212 int large_type<Dummy>::moved = 0;
    213 
    214 template <int Dummy>
    215 int large_type<Dummy>::const_copied = 0;
    216 
    217 template <int Dummy>
    218 int large_type<Dummy>::non_const_copied = 0;
    219 
    220 typedef large_type<> large;
    221 typedef large_type<1> large1;
    222 typedef large_type<2> large2;
    223 
    224 // The exception type thrown by 'small_throws_on_copy', 'large_throws_on_copy'
    225 // and 'throws_on_move'.
    226 struct my_any_exception {};
    227 
    228 void throwMyAnyExpression() {
    229 #if !defined(TEST_HAS_NO_EXCEPTIONS)
    230         throw my_any_exception();
    231 #else
    232         assert(false && "Exceptions are disabled");
    233 #endif
    234 }
    235 
    236 // A test type that will trigger the small object optimization within 'any'.
    237 // this type throws if it is copied.
    238 struct small_throws_on_copy
    239 {
    240     static int count;
    241     int value;
    242 
    243     explicit small_throws_on_copy(int val = 0) : value(val) {
    244         ++count;
    245     }
    246 
    247     small_throws_on_copy(small_throws_on_copy const &) {
    248         throwMyAnyExpression();
    249     }
    250 
    251     small_throws_on_copy(small_throws_on_copy && other) throw() {
    252         value = other.value;
    253         ++count;
    254     }
    255 
    256     ~small_throws_on_copy() {
    257         --count;
    258     }
    259 private:
    260     small_throws_on_copy& operator=(small_throws_on_copy const&) = delete;
    261     small_throws_on_copy& operator=(small_throws_on_copy &&) = delete;
    262 };
    263 
    264 int small_throws_on_copy::count = 0;
    265 
    266 // A test type that will NOT trigger the small object optimization within 'any'.
    267 // this type throws if it is copied.
    268 struct large_throws_on_copy
    269 {
    270     static int count;
    271     int value = 0;
    272 
    273     explicit large_throws_on_copy(int val = 0) : value(val) {
    274         data[0] = 0;
    275         ++count;
    276     }
    277 
    278     large_throws_on_copy(large_throws_on_copy const &) {
    279          throwMyAnyExpression();
    280     }
    281 
    282     large_throws_on_copy(large_throws_on_copy && other) throw() {
    283         value = other.value;
    284         ++count;
    285     }
    286 
    287     ~large_throws_on_copy() {
    288         --count;
    289     }
    290 
    291 private:
    292     large_throws_on_copy& operator=(large_throws_on_copy const&) = delete;
    293     large_throws_on_copy& operator=(large_throws_on_copy &&) = delete;
    294     int data[10];
    295 };
    296 
    297 int large_throws_on_copy::count = 0;
    298 
    299 // A test type that throws when it is moved. This object will NOT trigger
    300 // the small object optimization in 'any'.
    301 struct throws_on_move
    302 {
    303     static int count;
    304     int value;
    305 
    306     explicit throws_on_move(int val = 0) : value(val) { ++count; }
    307 
    308     throws_on_move(throws_on_move const & other) {
    309         value = other.value;
    310         ++count;
    311     }
    312 
    313     throws_on_move(throws_on_move &&) {
    314         throwMyAnyExpression();
    315     }
    316 
    317     ~throws_on_move() {
    318         --count;
    319     }
    320 private:
    321     throws_on_move& operator=(throws_on_move const&) = delete;
    322     throws_on_move& operator=(throws_on_move &&) = delete;
    323 };
    324 
    325 int throws_on_move::count = 0;
    326 
    327 
    328 #endif
    329