1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    TestDispatchers.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 // .NAME Test Dispatchers
16 // .SECTION Description
17 // Tests vtkDispatcher and vtkDoubleDispatcher
18 
19 #include "vtkObjectFactory.h"
20 #include "vtkDispatcher.h"
21 #include "vtkDoubleDispatcher.h"
22 #include "vtkDataArrayDispatcher.h"
23 #include "vtkNew.h"
24 
25 //classes we will be using in the test
26 #include "vtkCharArray.h"
27 #include "vtkDoubleArray.h"
28 #include "vtkStringArray.h"
29 #include "vtkIntArray.h"
30 #include "vtkPoints.h"
31 
32 #include <stdexcept>
33 #include <algorithm>
34 namespace
35 {
36 
test_expression(bool valid,const std::string & msg)37 void test_expression(bool valid, const std::string& msg)
38 {
39   if(!valid)
40   {
41     throw std::runtime_error(msg);
42   }
43 }
44 
45 template<typename T, typename U>
as(U * u)46 inline T* as(U* u)
47 {
48   return dynamic_cast<T*>(u);
49 }
50 
51 struct singleFunctor
52 {
53   int timesCalled;
singleFunctor__anon63e6b6c20111::singleFunctor54   singleFunctor():timesCalled(0){}
55   template<typename T>
operator ()__anon63e6b6c20111::singleFunctor56   int operator()(T&)
57   {
58     return ++timesCalled;
59   }
60 };
61 
62 struct doubleFunctor
63 {
64   int timesCalled;
doubleFunctor__anon63e6b6c20111::doubleFunctor65   doubleFunctor():timesCalled(0){}
66   template<typename T, typename U>
operator ()__anon63e6b6c20111::doubleFunctor67   int operator()(T&, U&)
68   {
69     return ++timesCalled;
70   }
71 };
72 
73 //type traits for vtkTTFunctor and pointsWrapper
74 template<typename T> struct FieldType;
75 template<> struct FieldType<vtkIntArray>
76 {
77   enum {VTK_DATA_TYPE=VTK_INT};
78   typedef int ValueType;
79 };
80 
81 template<> struct FieldType<vtkDoubleArray>
82 {
83   enum {VTK_DATA_TYPE=VTK_DOUBLE};
84   typedef double ValueType;
85 };
86 
87 template<> struct FieldType<vtkCharArray>
88 {
89   enum {VTK_DATA_TYPE=VTK_CHAR};
90   typedef char ValueType;
91 };
92 
93 //this functor replaces the usage of VTK_TT macro, by showing
94 //how to use template traits
95 struct vtkTTFunctor
96 {
97   template<typename T>
operator ()__anon63e6b6c20111::vtkTTFunctor98   void operator()(T& t) const
99   {
100     //example that sorts, only works on single component
101     typedef typename FieldType<T>::ValueType ValueType;
102     if(t.GetNumberOfComponents() == 1)
103     {
104       ValueType* start = static_cast<ValueType*>(t.GetVoidPointer(0));
105       ValueType* end = static_cast<ValueType*>(t.GetVoidPointer(
106                                                  t.GetNumberOfTuples()));
107       std::sort(start,end);
108     }
109   }
110 };
111 
112 struct pointsFunctor
113 {
operator ()__anon63e6b6c20111::pointsFunctor114   vtkPoints* operator()(vtkDoubleArray& dataArray) const
115   {
116     vtkPoints* points = vtkPoints::New();
117     points->SetData(&dataArray);
118     return points;
119   }
120 
operator ()__anon63e6b6c20111::pointsFunctor121   vtkPoints* operator()(vtkIntArray& dataArray) const
122   {
123     vtkPoints* points = vtkPoints::New();
124     points->SetNumberOfPoints(dataArray.GetNumberOfTuples());
125     return points;
126   }
127 };
128 
129 }
130 
TestSingleDispatch()131 bool TestSingleDispatch()
132 {
133   //statefull dispatching
134   singleFunctor functor;
135   vtkDispatcher<vtkObject,int> dispatcher;
136   dispatcher.Add<vtkDoubleArray>(&functor);
137   dispatcher.Add<vtkStringArray>(&functor);
138   dispatcher.Add<vtkIntArray>(&functor);
139 
140   //verify the dispatching
141   vtkNew<vtkDoubleArray> doubleArray;
142   vtkNew<vtkStringArray> stringArray;
143   vtkNew<vtkIntArray> intArray;
144   vtkNew<vtkPoints> pointsArray;
145 
146   int result = dispatcher.Go(as<vtkObject>(doubleArray.GetPointer()));
147   test_expression(result==1,"double array dispatch failed with statefull functor");
148 
149   result = dispatcher.Go(stringArray.GetPointer());
150   test_expression(result==2,"string array dispatch failed with statefull functor");
151 
152   result = dispatcher.Go(intArray.GetPointer());
153   test_expression(result==3,"int array dispatch failed with statefull functor");
154 
155   result = dispatcher.Go(pointsArray.GetPointer());
156   test_expression(result==0,"points array didn't fail");
157 
158   return true;
159 }
160 
TestStatelessSingleDispatch()161 bool TestStatelessSingleDispatch()
162 {
163   //stateless dispatching
164   vtkDispatcher<vtkObject,int> dispatcher;
165   dispatcher.Add<vtkDoubleArray>(singleFunctor());
166   dispatcher.Add<vtkStringArray>(singleFunctor());
167 
168   //verify the dispatching
169   vtkNew<vtkDoubleArray> doubleArray;
170   vtkNew<vtkStringArray> stringArray;
171 
172   int result = dispatcher.Go(doubleArray.GetPointer());
173   test_expression(result==1,"double array dispatch failed with stateless functor");
174 
175   result = dispatcher.Go(as<vtkObject>(stringArray.GetPointer()));
176   test_expression(result==1,"string array dispatch failed with stateless functor");
177 
178   return true;
179 }
180 
TestDoubleDispatch()181 bool TestDoubleDispatch()
182 {
183   //statefull dispatching
184   doubleFunctor functor;
185   vtkDoubleDispatcher<vtkObject,vtkObject,int> dispatcher;
186   dispatcher.Add<vtkDoubleArray,vtkStringArray>(&functor);
187   dispatcher.Add<vtkStringArray,vtkStringArray>(&functor);
188   dispatcher.Add<vtkIntArray,vtkDoubleArray>(&functor);
189 
190   //verify the dispatching
191   vtkNew<vtkDoubleArray> doubleArray;
192   vtkNew<vtkStringArray> stringArray;
193   vtkNew<vtkIntArray> intArray;
194   vtkNew<vtkPoints> pointsArray;
195 
196   int result = dispatcher.Go(as<vtkObject>(doubleArray.GetPointer()),
197                              as<vtkObject>(stringArray.GetPointer()));
198   test_expression(result==1,"double array dispatch failed with statefull functor");
199 
200   result = dispatcher.Go(stringArray.GetPointer(),stringArray.GetPointer());
201   test_expression(result==2,"string array dispatch failed with statefull functor");
202 
203   result = dispatcher.Go(as<vtkObject>(intArray.GetPointer()),doubleArray.GetPointer());
204   test_expression(result==3,"int array dispatch failed with statefull functor");
205 
206   result = dispatcher.Go(intArray.GetPointer(),pointsArray.GetPointer());
207   test_expression(result==0,"points array didn't fail");
208 
209   return true;
210 }
211 
TestStatelessDoubleDispatch()212 bool TestStatelessDoubleDispatch()
213 {
214   //stateless dispatching
215   vtkDoubleDispatcher<vtkObject,vtkObject,int> dispatcher;
216   dispatcher.Add<vtkDoubleArray,vtkStringArray>(doubleFunctor());
217   dispatcher.Add<vtkStringArray,vtkStringArray>(doubleFunctor());
218   dispatcher.Add<vtkIntArray,vtkDoubleArray>(doubleFunctor());
219 
220   //verify the dispatching
221   vtkNew<vtkDoubleArray> doubleArray;
222   vtkNew<vtkStringArray> stringArray;
223   vtkNew<vtkIntArray> intArray;
224   vtkNew<vtkPoints> pointsArray;
225 
226   int result = dispatcher.Go(doubleArray.GetPointer(),stringArray.GetPointer());
227   test_expression(result==1,"double array dispatch failed with statefull functor");
228 
229   result = dispatcher.Go(stringArray.GetPointer(),stringArray.GetPointer());
230   test_expression(result==1,"string array dispatch failed with statefull functor");
231 
232   result = dispatcher.Go(intArray.GetPointer(),doubleArray.GetPointer());
233   test_expression(result==1,"int array dispatch failed with statefull functor");
234 
235   result = dispatcher.Go(intArray.GetPointer(),pointsArray.GetPointer());
236   test_expression(result==0,"points array didn't fail");
237 
238   return true;
239 }
240 
241 
TestMixedDispatch()242 bool TestMixedDispatch()
243 {
244   //stateless dispatching
245   singleFunctor functor;
246   vtkDispatcher<vtkDataArray,int> dispatcher;
247   dispatcher.Add<vtkDoubleArray>(&functor);
248   dispatcher.Add<vtkIntArray>(&functor);
249   dispatcher.Add<vtkCharArray>(singleFunctor());
250 
251   //verify the dispatching
252   vtkNew<vtkDoubleArray> doubleArray;
253   vtkNew<vtkIntArray> intArray;
254   vtkNew<vtkCharArray> charArray;
255 
256   int result = dispatcher.Go(as<vtkDataArray>(doubleArray.GetPointer()));
257   result = dispatcher.Go(intArray.GetPointer());
258   test_expression(result==2,"unexpected");
259   result = dispatcher.Go(doubleArray.GetPointer());
260   test_expression(result==3,"statefull functor failed with int and double");
261 
262   result = dispatcher.Go(charArray.GetPointer());
263   test_expression(result==1,"");
264 
265 
266   return true;
267 }
268 
TestVTKTTReplacement()269 bool TestVTKTTReplacement()
270 {
271   //stateless dispatching
272   vtkDispatcher<vtkDataArray> dispatcher; //default return type is void
273   dispatcher.Add<vtkDoubleArray>(vtkTTFunctor());
274   dispatcher.Add<vtkIntArray>(vtkTTFunctor());
275 
276   //verify the dispatching
277   vtkNew<vtkDoubleArray> doubleArray;
278   vtkNew<vtkIntArray> intArray;
279 
280   doubleArray->SetNumberOfValues(10);
281   intArray->SetNumberOfValues(10);
282 
283   for(int i=0; i < 10; ++i)
284   {
285     doubleArray->SetValue(i,10-i);
286     intArray->SetValue(i,-10*i);
287   }
288 
289   //sort the array, passing in as vtkObject to show we use RTTI
290   //to get out the derived class info
291   dispatcher.Go(as<vtkDataArray>(doubleArray.GetPointer()));
292   dispatcher.Go(as<vtkDataArray>(intArray.GetPointer()));
293 
294   //verify the array is sorted, by checking min & max
295   test_expression(doubleArray->GetValue(0)==1,"double array not sorted");
296   test_expression(doubleArray->GetValue(9)==10,"double array not sorted");
297 
298   test_expression(intArray->GetValue(0)==-90,"int array not sorted");
299   test_expression(intArray->GetValue(9)==0,"int array not sorted");
300 
301   return true;
302 }
303 
TestReturnVtkObject()304 bool TestReturnVtkObject()
305 {
306   //This example shows how to return a vtkObject that is filled by the algorithm
307   //that you passed in.
308   vtkDispatcher<vtkDataArray,vtkPoints*> dispatcher; //default return type is void
309   dispatcher.Add<vtkDoubleArray>(pointsFunctor());
310   dispatcher.Add<vtkIntArray>(pointsFunctor());
311 
312   //verify the dispatching
313   vtkNew<vtkDoubleArray> doubleArray;
314   doubleArray->SetNumberOfComponents(3);
315   doubleArray->SetNumberOfTuples(1);
316 
317   //make sure the result isn't copied anywhere
318   vtkPoints* result = dispatcher.Go(as<vtkDataArray>(doubleArray.GetPointer()));
319 
320   test_expression(result != nullptr, "Returned points not valid");
321   test_expression(result->GetData() == doubleArray.GetPointer(),
322                   "Returned points not equal to the passed in double array");
323   result->Delete();
324 
325   //on an integer function we should get a whole new points array
326   vtkNew<vtkIntArray> intArray;
327   result = dispatcher.Go(as<vtkDataArray>( intArray.GetPointer() ));
328 
329   test_expression(result != nullptr, "Returned points not valid");
330   result->Delete();
331 
332   return true;
333 }
334 
335 
TestDispatchers(int,char * [])336 int TestDispatchers(int /*argc*/, char* /*argv*/[])
337 {
338 
339   bool passed = TestSingleDispatch();
340   passed &= TestStatelessSingleDispatch();
341   passed &= TestDoubleDispatch();
342   passed &= TestStatelessDoubleDispatch();
343   passed &= TestMixedDispatch();
344   passed &= TestVTKTTReplacement();
345   passed &= TestReturnVtkObject();
346 
347   return passed ? 0 : 1;
348 }
349