| 1 | /* |
| 2 | Copyright (c) 2005-2019 Intel Corporation |
| 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 | #define _VARIADIC_MAX 10 // Visual Studio 2012 |
| 18 | #include "harness.h" |
| 19 | #include "tbb/atomic.h" |
| 20 | #include "harness_checktype.h" |
| 21 | |
| 22 | #include "tbb/flow_graph.h" |
| 23 | #include <cstdio> |
| 24 | #include <stdexcept> |
| 25 | #include <vector> |
| 26 | |
| 27 | #if __TBB_GCC_STRICT_ALIASING_BROKEN |
| 28 | #pragma GCC diagnostic ignored "-Wstrict-aliasing" |
| 29 | #endif |
| 30 | |
| 31 | // given a tuple, return the type of the element that has the maximum alignment requirement. |
| 32 | // Given a tuple and that type, return the number of elements of the object with the max |
| 33 | // alignment requirement that is at least as big as the largest object in the tuple. |
| 34 | |
| 35 | using tbb::flow::tuple_element; |
| 36 | using tbb::flow::tuple_size; |
| 37 | using tbb::flow::cast_to; |
| 38 | using tbb::flow::is_a; |
| 39 | |
| 40 | typedef int *int_ptr; |
| 41 | typedef char odd_array_type[15]; |
| 42 | typedef char odder_array[17]; |
| 43 | typedef check_type<int> counted_array_type[12]; |
| 44 | typedef std::vector<double> d_vector; |
| 45 | typedef std::vector<int> i_vector; |
| 46 | typedef i_vector i_vector_array[2]; |
| 47 | typedef tbb::flow::tagged_msg<size_t, int, char, double, odd_array_type, odder_array, d_vector, check_type<int>, counted_array_type, i_vector_array> tagged_msg_type; |
| 48 | |
| 49 | // test base of tagged_msg |
| 50 | void TestWrapper() { |
| 51 | using tbb::flow::interface10::internal::Wrapper; |
| 52 | Wrapper<int> wi(42); |
| 53 | Wrapper<int> wic(23); |
| 54 | |
| 55 | REMARK("Value of wic is %d\n" , wic.value()); |
| 56 | |
| 57 | // pointer-type creation |
| 58 | int point_to_me = 23; |
| 59 | Wrapper<int_ptr> wip(&point_to_me); |
| 60 | ASSERT(*(wip.value()) == 23, "Error in wip value" ); |
| 61 | |
| 62 | odd_array_type ww; |
| 63 | for(int ii = 0; ii < 15; ++ii) { ww[ii] = char('0' + ii); } ww[14] = 0; |
| 64 | |
| 65 | Wrapper<odd_array_type> ci(ww); |
| 66 | ASSERT(!strncmp(ci.value(), ww, 14), "odd_array_type ci not properly-constructed" ); |
| 67 | |
| 68 | Wrapper<odd_array_type> ci2(ci); |
| 69 | |
| 70 | ASSERT(!strncmp(ci2.value(), ww, 14), "odd_array_type ci2 not properly-constructed" ); |
| 71 | |
| 72 | d_vector di; |
| 73 | di.clear(); |
| 74 | di.push_back(2.0); |
| 75 | Wrapper<d_vector> dvec(di); |
| 76 | ASSERT(dvec.value()[0] == 2.0, "incorrect value in vector" ); |
| 77 | |
| 78 | // test array of non-PODs. |
| 79 | i_vector_array oia; |
| 80 | oia[0].clear(); |
| 81 | oia[1].clear(); |
| 82 | oia[0].push_back(3); |
| 83 | oia[1].push_back(2); |
| 84 | Wrapper<i_vector_array> ia(oia); |
| 85 | ASSERT((ia.value()[1])[0] == 2, "integer vector array element[1] misbehaved" ); |
| 86 | ASSERT((ia.value()[0])[0] == 3, "integer vector array element[0] misbehaved" ); |
| 87 | Wrapper<i_vector_array> iac(ia); |
| 88 | ASSERT((iac.value()[1])[0] == 2, "integer vector array element[1] misbehaved" ); |
| 89 | ASSERT((iac.value()[0])[0] == 3, "integer vector array element[0] misbehaved" ); |
| 90 | |
| 91 | // counted_array |
| 92 | counted_array_type cat_orig; |
| 93 | for(int i = 0; i < 12; ++i) cat_orig[i] = i + 1; |
| 94 | Wrapper<counted_array_type> cat(cat_orig); |
| 95 | for(int j = 0; j < 12; ++j) |
| 96 | ASSERT(1 + j == cat.value()[j], "Error in cat array" ); |
| 97 | |
| 98 | int i = wi.value(); |
| 99 | ASSERT(i == 42, "Assignment to i failed" ); |
| 100 | ASSERT(wi.value() == 42, "Assignment to wi failed" ); |
| 101 | double d = wi.value(); |
| 102 | ASSERT(d == 42, "Implicit cast in assign to double failed" ); |
| 103 | int_ptr ip = wip.value(); |
| 104 | ASSERT(ip == &(point_to_me), "Error in assignment of pointer" ); |
| 105 | } |
| 106 | |
| 107 | void RunTests() { |
| 108 | tagged_msg_type def; |
| 109 | tagged_msg_type i(1,3); |
| 110 | check_type<int>::check_type_counter = 0; |
| 111 | int z; |
| 112 | #if TBB_USE_EXCEPTIONS |
| 113 | try { |
| 114 | z = cast_to<int>(def); // disallowed (non-array returning int) |
| 115 | ASSERT(false, "should not allow cast to int of non-array" ); |
| 116 | } |
| 117 | catch(...) { |
| 118 | REMARK("cast of non-array to int disallowed (okay)\n" ); |
| 119 | } |
| 120 | #endif |
| 121 | z = cast_to<int>(i); |
| 122 | ASSERT(is_a<int>(i), "wrong type for i ( == int)" ); |
| 123 | ASSERT(!(is_a<double>(i)), "Wrong type for i ( != double)" ); |
| 124 | z = 5; |
| 125 | z = cast_to<int>(i); |
| 126 | |
| 127 | const int &ref_i(cast_to<int>(i)); |
| 128 | ASSERT(ref_i == 3, "ref_i got wrong value" ); |
| 129 | tagged_msg_type j(2,4); |
| 130 | i = j; |
| 131 | ASSERT(ref_i == 4, "assign to i did not affect ref_i" ); |
| 132 | |
| 133 | ASSERT( z == 3, "Error retrieving value from i" ); |
| 134 | |
| 135 | //updating and retrieving tags |
| 136 | ASSERT(j.tag() == 2, "Error retrieving tag for j" ); |
| 137 | j.set_tag(10); |
| 138 | ASSERT(j.tag() == 10, "Error updating tag for j" ); |
| 139 | |
| 140 | tbb::flow::tagged_msg<char, int, char, double> k('a', 4); |
| 141 | k.set_tag('b'); |
| 142 | ASSERT(k.tag() == 'b', "Error updating char tag" ); |
| 143 | |
| 144 | tagged_msg_type double_tagged_msg(3, 8.0); |
| 145 | ASSERT(is_a<double>(double_tagged_msg), "Wrong type for double_tagged_msg (== double)" ); |
| 146 | ASSERT(!is_a<char>(double_tagged_msg), "Wrong type for double_tagged_msg (!= char)" ); |
| 147 | ASSERT(!is_a<int>(double_tagged_msg), "Wrong type for double_tagged_msg (!= int)" ); |
| 148 | tagged_msg_type copytype(double_tagged_msg); |
| 149 | ASSERT(is_a<double>(copytype), "Wrong type for double_tagged_msg (== double)" ); |
| 150 | ASSERT(!is_a<char>(copytype), "Wrong type for double_tagged_msg (!= char)" ); |
| 151 | ASSERT(!is_a<int>(copytype), "Wrong type for double_tagged_msg (!= int)" ); |
| 152 | tagged_msg_type default_tagged_msg; |
| 153 | ASSERT(!(is_a<double>(default_tagged_msg)), "wrong type for default ( != double)" ); |
| 154 | ASSERT(!(is_a<int>(default_tagged_msg)), "wrong type for default ( != int)" ); |
| 155 | ASSERT(!(is_a<bool>(default_tagged_msg)), "wrong type for default ( != bool)" ); |
| 156 | check_type<int> c; |
| 157 | ASSERT(check_type<int>::check_type_counter == 1, "Incorrect number of check_type<int>s created" ); |
| 158 | tagged_msg_type cnt_type(4, c); |
| 159 | ASSERT(check_type<int>::check_type_counter == 2, "Incorrect number of check_type<int>s created" ); |
| 160 | ASSERT(is_a<check_type<int> >(cnt_type), "Incorrect type for cnt_type" ); |
| 161 | cnt_type = default_tagged_msg; |
| 162 | ASSERT(check_type<int>::check_type_counter == 1, "Incorrect number of check_type<int>s after reassignment" ); |
| 163 | ASSERT(cnt_type.is_default_constructed(), "Assigned check_type<int>s is not default-constructed" ); |
| 164 | // having problem with init on gcc 3.4.6 (fxeolin16) constructor for elements of array not called |
| 165 | // for this version. |
| 166 | // counted_array_type counted_array; |
| 167 | check_type<int> counted_array[12]; // this is okay |
| 168 | ASSERT(check_type<int>::check_type_counter == 13, "Incorrect number of check_type<int>s after counted_array construction" ); |
| 169 | tagged_msg_type counted_array_tagged_msg(5, counted_array); |
| 170 | // the is_a<>() should return exact type matches. |
| 171 | ASSERT(!is_a<check_type<int> *>(counted_array_tagged_msg), "Test of is_a for counted_array_tagged_msg fails" ); |
| 172 | #if TBB_USE_EXCEPTIONS |
| 173 | try { |
| 174 | int *iip = cast_to<int *>(counted_array_tagged_msg); |
| 175 | ASSERT(false, "did not throw on invalid cast" ); |
| 176 | *iip = 2; // avoids "iip set but not used" warning |
| 177 | } |
| 178 | catch(std::runtime_error &re) { |
| 179 | REMARK("attempt to cast to invalid type caught %s\n" , re.what()); |
| 180 | } |
| 181 | ASSERT(is_a<counted_array_type>(counted_array_tagged_msg), "testing" ); |
| 182 | const check_type<int> *ctip = cast_to<counted_array_type>(counted_array_tagged_msg); |
| 183 | |
| 184 | ASSERT((int)(*ctip) == 0, "ctip incorrect" ); |
| 185 | |
| 186 | ASSERT(check_type<int>::check_type_counter == 25, "Incorrect number of check_type<int>s after counted_array_tagged_msg construction" ); |
| 187 | counted_array_tagged_msg = default_tagged_msg; |
| 188 | ASSERT(check_type<int>::check_type_counter == 13, "Incorrect number of check_type<int>s after counted_array_tagged_msg destruction" ); |
| 189 | ASSERT(counted_array_tagged_msg.is_default_constructed(), "Assigned counted_array_type is not default-constructed" ); |
| 190 | |
| 191 | default_tagged_msg = double_tagged_msg; |
| 192 | const double my_dval = cast_to<double>(default_tagged_msg); |
| 193 | ASSERT(my_dval == 8.0, "did not retrieve correct value from assigned default_tagged_msg" ); |
| 194 | |
| 195 | { |
| 196 | odd_array_type my_b; |
| 197 | for(size_t ii=0; ii < 14;++ii) { |
| 198 | my_b[ii] = (char)('0' + ii); |
| 199 | } |
| 200 | my_b[14] = 0; |
| 201 | { |
| 202 | tagged_msg_type odd_array_tagged_msg(6, my_b); |
| 203 | const char *my_copy = cast_to<odd_array_type>(odd_array_tagged_msg); |
| 204 | ASSERT(!strncmp(my_b, my_copy, 14), "copied char array not correct value" ); |
| 205 | default_tagged_msg = odd_array_tagged_msg; |
| 206 | try { |
| 207 | const char *my_copy2 = cast_to<odd_array_type>(default_tagged_msg); |
| 208 | ASSERT(!strncmp(my_b, my_copy2, 14), "char array from default tagged_msg assign not correct value" ); |
| 209 | } |
| 210 | catch(...) { |
| 211 | ASSERT(false, "Bad cast" ); |
| 212 | } |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | ASSERT(!is_a<double>(i), "bad type for i" ); |
| 217 | try { |
| 218 | double y = cast_to<double>(i); |
| 219 | // use '&' to force eval of RHS (fixes "initialized but not referenced" vs2012 warnings) |
| 220 | ASSERT(false & (0 != y), "Error: cast to type in tuple did not get exception" ); |
| 221 | } |
| 222 | catch(std::runtime_error &bc) { |
| 223 | ASSERT(0 == strcmp(bc.what(), "Illegal tagged_msg cast" ), "Incorrect std:runtime_error" ); |
| 224 | } |
| 225 | catch(...) { |
| 226 | ASSERT(false & cast_to<int>(i), "Error: improper exception thrown" ); |
| 227 | } |
| 228 | |
| 229 | try { |
| 230 | int *ip = cast_to<int *>(i); |
| 231 | ASSERT(false & (NULL!=ip), "Error: non-array cast to pointer type." ); |
| 232 | } |
| 233 | catch(std::runtime_error &bc) { |
| 234 | ASSERT(0 == strcmp(bc.what(), "Illegal tagged_msg cast" ), "Incorrect std:runtime_error" ); |
| 235 | } |
| 236 | catch(...) { |
| 237 | ASSERT(false, "did not get runtime_error exception in casting non-array to pointer" ); |
| 238 | } |
| 239 | |
| 240 | try { |
| 241 | bool b = cast_to<bool>(i); |
| 242 | ASSERT(false & b, "Error: cast against type did not get exception" ); |
| 243 | } |
| 244 | catch(std::runtime_error &bc) { |
| 245 | ASSERT(0 == strcmp(bc.what(), "Illegal tagged_msg cast" ), "Incorrect std:runtime_error" ); |
| 246 | } |
| 247 | catch(...) { |
| 248 | ASSERT(false, "did not get runtime_error exception casting to disparate types" ); |
| 249 | } |
| 250 | #endif //TBB_USE_EXCEPTIONS |
| 251 | } |
| 252 | |
| 253 | int TestMain() { |
| 254 | TestWrapper(); |
| 255 | ASSERT(check_type<int>::check_type_counter == 0, "After TestWrapper return not all check_type<int>s were destroyed" ); |
| 256 | RunTests(); |
| 257 | ASSERT(check_type<int>::check_type_counter == 0, "After RunTests return not all check_type<int>s were destroyed" ); |
| 258 | return Harness::Done; |
| 259 | } |
| 260 | |