1 /*
2     Copyright (c) 2005-2020 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
TestWrapper()50 void TestWrapper() {
51     using tbb::flow::interface11::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 
RunTests()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 
TestMain()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