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