0026922: Huge performance issue writing data to the output stream
[occt.git] / src / QANCollection / QANCollection_Handle.cxx
1 // Copyright (c) 2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <QANCollection.hxx>
15
16 #include <Draw.hxx>
17 #include <Draw_Interpretor.hxx>
18
19 #include <Message_Status.hxx>
20 #include <NCollection_StdAllocator.hxx>
21 #include <NCollection_IncAllocator.hxx>
22 #include <NCollection_HeapAllocator.hxx>
23 #include <OSD_Timer.hxx>
24 #include <Standard_Assert.hxx>
25 #include <Standard_DefineHandle.hxx>
26 #include <Standard_Transient.hxx>
27 #include <TCollection_AsciiString.hxx>
28 #include <Geom_Line.hxx>
29 #include <Geom_BSplineCurve.hxx>
30 #include <Geom_Surface.hxx>
31
32 #include <vector>
33 #include <memory>
34 #include <typeinfo>
35
36 // auxiliary macro to check and report status
37 #define CHECK(di,ok,what) di << "Checking " << what << (ok ? ": OK\n" : ": Error\n")
38
39 //=======================================================================
40 //function : QAHandleOps
41 //purpose  : Test Handle operations (mostly compile-time checks)
42 //=======================================================================
43
44 // set of overloaded functions for checking resolution of arguments
45 inline void f (const Handle(Geom_Curve)&) {}
46 inline void func (const Handle(Geom_Curve)&) {}
47 inline void func (const Handle(Geom_BSplineCurve)&) {}
48 inline void func (const Handle(Geom_Surface)&) {}
49 inline void func (const Handle(gp_Pnt)&) {}
50 inline void func (const Handle(gp_XYZ)&) {}
51 inline void func (const Handle(gp_Trsf)&) {}
52
53 inline void gunc (Handle(Geom_Curve)&) {}
54
55 static Standard_Integer QAHandleOps (Draw_Interpretor& theDI,
56                                      Standard_Integer  /*theArgNb*/,
57                                      const char**      /*theArgVec*/)
58 {
59   // ===============================================================
60   // Part 1: classes inheriting transient
61   // ===============================================================
62
63   Handle(Geom_Line) aLine = new Geom_Line (gp::Origin(), gp::DZ());
64   CHECK(theDI, ! aLine.IsNull(), "handle for non-null");
65
66   const Handle(Geom_Line)& cLine = aLine; // cast to self const ref
67   const Handle(Geom_Curve)& cCurve = aLine; // cast to base const ref
68   Geom_Line* pLine = aLine.get();
69   const Geom_Line* cpLine = aLine.get();
70   Geom_Line& rLine = *aLine;
71   const Geom_Line& crLine = *cLine;
72   Handle(Geom_Curve) aCurve = aLine; // copy from handle to derived type
73   aCurve = cLine; // assignment to handle of derived type
74   Handle(Geom_Line) dLine (cpLine); // copy from handle to derived type
75
76   aLine = Handle(Geom_Line)::DownCast (cCurve);
77   CHECK(theDI, ! aLine.IsNull(), "down cast");
78
79   // comparison operators
80   CHECK(theDI, aLine == aLine, "equality of handle to itself");
81   CHECK(theDI, cLine == cLine, "equality of const handle to itself");
82   CHECK(theDI, aLine == cLine, "equality of const and non-const handle");
83   CHECK(theDI, aLine == cCurve, "equality of handle and base handle");
84   CHECK(theDI, aLine == pLine,  "equality of handle and pointer");
85   CHECK(theDI, pLine == aLine,  "equality of pointer and handle");
86   CHECK(theDI, aLine == cpLine,  "equality of handle and const pointer");
87   CHECK(theDI, cpLine == aLine,  "equality of const pointer and handle");
88   CHECK(theDI, &rLine == aLine,  "equality of reference and handle");
89   CHECK(theDI, &crLine == aLine,  "equality of reference and handle");
90   CHECK(theDI, aLine, "cast to bool");
91
92   Handle(Geom_Line) aLin2;
93   CHECK(theDI, aLine != aLin2, "inequality of handle to the same type handle");
94   CHECK(theDI, aLin2 != cLine, "inequality of const and non-const handle");
95   CHECK(theDI, aLin2 != cCurve, "inequality of handle and base handle");
96   CHECK(theDI, aLin2 != pLine,  "inequality of handle and pointer");
97   CHECK(theDI, pLine != aLin2,  "inequality of pointer and handle");
98   CHECK(theDI, aLin2 != cpLine,  "inequality of handle and const pointer");
99   CHECK(theDI, cpLine != aLin2,  "inequality of const pointer and handle");
100
101   Handle(Geom_Curve) aCur2;
102   CHECK(theDI, aLine != aCur2, "inequality of handles of different types");
103   CHECK(theDI, aCur2 != cLine, "inequality of const and non-const handle");
104   CHECK(theDI, aCur2 != cCurve, "inequality of handle and base handle");
105   CHECK(theDI, aCur2 != pLine,  "inequality of handle and pointer");
106   CHECK(theDI, pLine != aCur2,  "inequality of pointer and handle");
107   CHECK(theDI, aCur2 != cpLine,  "inequality of handle and const pointer");
108   CHECK(theDI, cpLine != aCur2,  "inequality of const pointer and handle");
109
110   // passing handle as reference to base class
111   f (aLine);
112
113   // passing handle to overloaded function accepting handle to another type
114   // will fail on VC below 12 and GCC below 4.3 due to ambiguity of overloads
115 #if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800) || (defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 3)
116   func (aLine);
117   func (cLine);
118 #endif
119
120   // passing handle as non-const reference to base type
121   // currently allowed for compatibility
122   gunc (aLine);
123   Handle(Geom_Curve)& aCurve2 = aLine; // cast to base non-const ref
124
125   Handle(Geom_Line) qLine = cpLine; // constructor from const pointer -- could be made explicit...
126
127   // check whether compiler will destroy reference to temporary handle
128   const Handle(Geom_Curve)& aTmpRef (Handle(Geom_Line)::DownCast (aCurve2));
129   CHECK(theDI, ! aTmpRef.IsNull(),  "local reference of handle to base type to temporary handle object");
130
131   Handle(Geom_Surface) aSurf;
132   (void)aSurf;
133
134 #if 0
135   // each test in this section must cause compiler error
136   gunc (cLine); // passing const handle as non-const reference to base type
137   pLine = cLine.get(); // getting non-const pointer to contained object from const handle 
138   Handle(Geom_Line) xLine = cCurve; // copy from handle to base type
139   Handle(Geom_BSplineCurve) aBSpl (new Geom_Line (gp::Origin(), gp::DX())); // construction from pointer to incompatible type
140
141   CHECK(theDI, aLine == aSurf, "equality of handles of incompatible types");
142   CHECK(theDI, aSurf == cLine, "equality of const and non-const handle");
143   CHECK(theDI, aSurf == cCurve, "equality of handle and base handle");
144   CHECK(theDI, aSurf == pLine,  "equality of handle and pointer");
145   CHECK(theDI, pLine == aSurf,  "equality of pointer and handle");
146   CHECK(theDI, aSurf == cpLine,  "equality of handle and const pointer");
147   CHECK(theDI, cpLine != aSurf,  "equality of const pointer and handle");
148
149   CHECK(theDI, aLine != aSurf, "inequality of handles of incompatible types");
150   CHECK(theDI, aSurf != cLine, "inequality of const and non-const handle");
151   CHECK(theDI, aSurf != cCurve, "inequality of handle and base handle");
152   CHECK(theDI, aSurf != pLine,  "inequality of handle and pointer");
153   CHECK(theDI, pLine != aSurf,  "inequality of pointer and handle");
154   CHECK(theDI, aSurf != cpLine,  "inequality of handle and const pointer");
155   CHECK(theDI, cpLine != aSurf,  "inequality of const pointer and handle");
156 #endif
157
158   // ===============================================================
159   // Part 2: classes not inheriting transient
160   // ===============================================================
161 /*
162   Handle(gp_Pnt) aPnt = new gp_Pnt (gp::Origin());
163   CHECK(theDI, ! aPnt.IsNull(), "handle for non-null");
164
165   const Handle(gp_Pnt)& cPnt = aPnt; // cast to self const ref
166 //  const Handle(gp_XYZ)& cXYZ = aPnt; // cast to base const ref
167   gp_Pnt* pPnt = aPnt.get();
168   const gp_Pnt* cpPnt = aPnt.get();
169   gp_Pnt& rPnt = *aPnt;
170   const gp_Pnt& crPnt = *cPnt;
171 //  Handle(gp_XYZ) aXYZ = aPnt; // copy from handle to derived type
172 //  aXYZ = cPnt; // assignment to handle of derived type
173
174 //  aPnt = Handle(gp_Pnt)::DownCast (cXYZ);
175 //  CHECK(theDI, ! aPnt.IsNull(), "down cast");
176
177   // comparison operators
178   CHECK(theDI, aPnt == aPnt, "equality of handle to itself");
179   CHECK(theDI, cPnt == cPnt, "equality of const handle to itself");
180   CHECK(theDI, aPnt == cPnt, "equality of const and non-const handle");
181 //  CHECK(theDI, aPnt == cXYZ, "equality of handle and base handle");
182   CHECK(theDI, aPnt == pPnt,  "equality of handle and pointer");
183   CHECK(theDI, pPnt == aPnt,  "equality of pointer and handle");
184   CHECK(theDI, aPnt == cpPnt,  "equality of handle and const pointer");
185   CHECK(theDI, cpPnt == aPnt,  "equality of const pointer and handle");
186   CHECK(theDI, &rPnt == aPnt,  "equality of reference and handle");
187   CHECK(theDI, &crPnt == aPnt,  "equality of reference and handle");
188
189   Handle(gp_Pnt) aPnt2;
190   CHECK(theDI, aPnt != aPnt2, "inequality of handle to the same type handle");
191   CHECK(theDI, aPnt2 != cPnt, "inequality of const and non-const handle");
192 //  CHECK(theDI, aPnt2 != cXYZ, "inequality of handle and base handle");
193   CHECK(theDI, aPnt2 != pPnt,  "inequality of handle and pointer");
194   CHECK(theDI, pPnt != aPnt2,  "inequality of pointer and handle");
195   CHECK(theDI, aPnt2 != cpPnt,  "inequality of handle and const pointer");
196   CHECK(theDI, cpPnt != aPnt2,  "inequality of const pointer and handle");
197
198   Handle(gp_XYZ) aXYZ2;
199   CHECK(theDI, aLine != aPnt2, "inequality of handles of different types");
200   CHECK(theDI, aXYZ2 != cPnt, "inequality of const and non-const handle");
201 //  CHECK(theDI, aXYZ2 != cXYZ, "inequality of handle and base handle");
202 //  CHECK(theDI, aXYZ2 != pPnt,  "inequality of handle and pointer");
203 //  CHECK(theDI, pPnt != aXYZ2,  "inequality of pointer and handle");
204 //  CHECK(theDI, aXYZ2 != cpPnt,  "inequality of handle and const pointer");
205 //  CHECK(theDI, cpPnt != aXYZ2,  "inequality of const pointer and handle");
206
207   // passing handle as reference to base class
208   func (aPnt);
209   func (cPnt);
210 */
211   return 0;
212 }
213
214 //=======================================================================
215 //function : QAHandleBool
216 //purpose  : Test Handle -> bool conversion
217 //=======================================================================
218 static Standard_Integer QAHandleBool (Draw_Interpretor& theDI,
219                                       Standard_Integer  /*theArgNb*/,
220                                       const char**      /*theArgVec*/)
221 {
222   Handle(NCollection_BaseAllocator) aPtr = new NCollection_IncAllocator();
223
224   Handle(NCollection_IncAllocator) anInc = Handle(NCollection_IncAllocator)::DownCast (aPtr);
225   CHECK (theDI, ! anInc.IsNull(), "cast to NCollection_IncAllocator");
226
227   Handle(NCollection_BaseAllocator) anAlloc = Handle(NCollection_BaseAllocator)::DownCast (aPtr);
228   CHECK (theDI, ! anAlloc.IsNull(), "cast to NCollection_BaseAllocator");
229   
230   Handle(NCollection_HeapAllocator) aHAlloc = Handle(NCollection_HeapAllocator)::DownCast (aPtr);
231   CHECK (theDI, aHAlloc.IsNull(), "cast to NCollection_HeapAllocator");
232
233   return 0;
234 }
235
236 // Auxiliary class to define new virtual methods
237 class Transient_Root : public Standard_Transient
238 {
239 public:
240   virtual const char* Name() const { return "Transient_Root"; }
241   virtual Standard_Transient* CreateParent() const { return new Standard_Transient; }
242   virtual Standard_Transient* Clone()        const { return new Transient_Root; }
243   DEFINE_STANDARD_RTTI(Transient_Root, Standard_Transient)
244 };
245 DEFINE_STANDARD_HANDLE(Transient_Root, Standard_Transient)
246
247 // Auxiliary macros to create hierarchy of 50 classes
248 #define QA_DEFINECLASS(theClass, theParent) \
249 class theClass : public theParent \
250 { \
251 public:\
252   virtual const char* Name() const Standard_OVERRIDE { return #theClass; } \
253   virtual Standard_Transient* CreateParent() const Standard_OVERRIDE { return new theParent(); } \
254   virtual Standard_Transient* Clone()        const Standard_OVERRIDE { return new theClass(); } \
255   DEFINE_STANDARD_RTTI(theClass, theParent) \
256 };\
257 DEFINE_STANDARD_HANDLE    (theClass, theParent) \
258 IMPLEMENT_STANDARD_HANDLE (theClass, theParent) \
259 IMPLEMENT_STANDARD_RTTIEXT(theClass, theParent)
260
261 #define QA_NAME(theNum) qaclass ## theNum ## _ ## 50
262 #define QA_HANDLE_NAME(theNum) Handle(qaclass ## theNum ## _ ## 50)
263
264 #define QA_DEFINECLASS10(theParent, theTens) \
265 QA_DEFINECLASS(QA_NAME(theTens ## 0), theParent) \
266 QA_DEFINECLASS(QA_NAME(theTens ## 1), QA_NAME(theTens ## 0)) \
267 QA_DEFINECLASS(QA_NAME(theTens ## 2), QA_NAME(theTens ## 1)) \
268 QA_DEFINECLASS(QA_NAME(theTens ## 3), QA_NAME(theTens ## 2)) \
269 QA_DEFINECLASS(QA_NAME(theTens ## 4), QA_NAME(theTens ## 3)) \
270 QA_DEFINECLASS(QA_NAME(theTens ## 5), QA_NAME(theTens ## 4)) \
271 QA_DEFINECLASS(QA_NAME(theTens ## 6), QA_NAME(theTens ## 5)) \
272 QA_DEFINECLASS(QA_NAME(theTens ## 7), QA_NAME(theTens ## 6)) \
273 QA_DEFINECLASS(QA_NAME(theTens ## 8), QA_NAME(theTens ## 7)) \
274 QA_DEFINECLASS(QA_NAME(theTens ## 9), QA_NAME(theTens ## 8))
275
276 QA_DEFINECLASS10(Transient_Root,     0)
277 QA_DEFINECLASS10(qaclass09_50,       1)
278 QA_DEFINECLASS10(qaclass19_50,       2)
279 QA_DEFINECLASS10(qaclass29_50,       3)
280 QA_DEFINECLASS10(qaclass39_50,       4)
281 QA_DEFINECLASS  (qaclass50_50, qaclass49_50)
282
283 namespace
284 {
285   class qaclass50_50ANON : public qaclass49_50
286   {
287   public:
288     qaclass50_50ANON() {}
289   };
290 }
291
292 namespace QaNamespace
293 {
294   class qaclass50_50 : public qaclass49_50
295   {
296   public:
297     qaclass50_50() {}
298   };
299 }
300
301 namespace {
302 //! Timer sentry. Prints elapsed time information at destruction time.
303 class QATimer : public OSD_Timer
304 {
305 public:
306   enum TimeFormat
307   {
308     Seconds,
309     Milliseconds,
310     Microseconds,
311     Nanoseconds,
312     s  = Seconds,
313     ms = Milliseconds,
314     ns = Nanoseconds,
315   };
316
317 public:
318   //! Main constructor - automatically starts the timer.
319   QATimer (Draw_Interpretor& theDI,
320            Standard_CString       theTitle,
321            const TimeFormat       theFormat,
322            const Standard_Integer theNbIters = 1,
323            const Standard_Boolean theToPrintFormat = Standard_False)
324   : myDI(&theDI),
325     myTitle         (theTitle),
326     myFormat        (theFormat),
327     myNbIters       (theNbIters),
328     myToPrintFormat (theToPrintFormat)
329   {
330     Start();
331   }
332
333   //! Destructor - stops the timer and prints statistics.
334   ~QATimer()
335   {
336     Stop();
337     if (myTitle != NULL)
338     {
339       (*myDI) << myTitle;
340     }
341     switch (myFormat)
342     {
343       case Seconds:
344         (*myDI) <<  ElapsedTime() / Standard_Real(myNbIters);
345         if (myToPrintFormat)
346         {
347           (*myDI) << " s";
348         }
349         break;
350       case Milliseconds:
351         (*myDI) << (ElapsedTime() / Standard_Real(myNbIters)) * 1000.0;
352         if (myToPrintFormat)
353         {
354           (*myDI) << " ms";
355         }
356         break;
357       case Microseconds:
358         (*myDI) << (ElapsedTime() / Standard_Real(myNbIters)) * 1000000.0;
359         if (myToPrintFormat)
360         {
361           (*myDI) << " microseconds";
362         }
363         break;
364       case Nanoseconds:
365         (*myDI) << (ElapsedTime() / Standard_Real(myNbIters)) * 1000000000.0;
366         if (myToPrintFormat)
367         {
368           (*myDI) << " ns";
369         }
370         break;
371     }
372   }
373
374 private:
375   Draw_Interpretor* myDI;
376   Standard_CString myTitle;         //!< timer description
377   TimeFormat       myFormat;        //!< time format
378   Standard_Integer myNbIters;       //!< iterations number
379   Standard_Boolean myToPrintFormat; //!< add time format
380 };
381 } // anonymous namespace
382
383 //=======================================================================
384 //function : QAHandleInc
385 //purpose  : Estimate the smart-pointer counter incrementing time
386 //=======================================================================
387 static Standard_Integer QAHandleInc (Draw_Interpretor& theDI,
388                                      Standard_Integer  theArgNb,
389                                      const char**      theArgVec)
390 {
391   if (theArgNb > 2)
392   {
393     std::cout << "Error: wrong syntax! See usage:\n";
394     theDI.PrintHelp (theArgVec[0]);
395     return 1;
396   }
397   const Standard_Integer aNbIters = (theArgNb > 1) ? Draw::Atoi (theArgVec[1]) : 10000000;
398   if (aNbIters < 1)
399   {
400     std::cout << "Error: number of iterations should be positive!\n";
401     return 1;
402   }
403
404   Handle(Standard_Transient) aHandle  = new Standard_Transient();
405   std::shared_ptr<Standard_Transient> aSharePtr (new Standard_Transient());
406   theDI << "Time of creating and destroying " << aNbIters << " smart pointers to the same object, per item, ns:";
407   {
408     {
409       QATimer aTimer (theDI, "\nOCCT Handle: ", QATimer::ns, aNbIters);
410       {
411         std::vector<Handle(Standard_Transient)> aHandles (aNbIters);
412         for (Standard_Integer anIter = 0; anIter < aNbIters; ++anIter)
413         {
414           aHandles[anIter] = aHandle;
415         }
416       }
417     }
418     {
419       QATimer aTimer (theDI, "\nsC++ shared_ptr: ", QATimer::ns, aNbIters);
420       {
421         std::vector< std::shared_ptr<Standard_Transient> > aSharePointers (aNbIters);
422         for (Standard_Integer anIter = 0; anIter < aNbIters; ++anIter)
423         {
424           aSharePointers[anIter] = aSharePtr;
425         }
426       }
427     }
428   }
429   return 0;
430 }
431
432 namespace
433 {
434   //! Auxiliary class to perform casting to specified type.
435   template<typename TTo> struct QACast
436   {
437     //! Perform casting using OCCT DownCast() operation.
438     template<typename TFrom>
439     static void doDownCast (Draw_Interpretor& theDI,
440                             const Standard_Integer theNbIters,
441                             const TFrom&           theHandle)
442     {
443       std::vector<TTo> aHandles (theNbIters);
444       {
445         QATimer aTimer (theDI, " ", QATimer::ns, theNbIters);
446         for (Standard_Integer anIter = 0; anIter < theNbIters; ++anIter)
447         {
448           aHandles[anIter] = TTo::DownCast (theHandle);
449         }
450       }
451     }
452
453     //! Perform casting using standard C++ dynamic_cast<> operation.
454     template<typename TFrom>
455     static void doDynamicCast (Draw_Interpretor& theDI,
456                                const Standard_Integer theNbIters,
457                                const TFrom&           theHandle)
458     {
459       std::vector<typename TTo::element_type*> aPointers (theNbIters);
460       {
461         QATimer aTimer (theDI, " ", QATimer::ns, theNbIters);
462         for (Standard_Integer anIter = 0; anIter < theNbIters; ++anIter)
463         {
464           aPointers[anIter] = dynamic_cast<typename TTo::element_type* > (theHandle.operator->());
465         }
466       }
467     }
468
469     //! Perform dynamic casting using shared_ptr::dynamic_pointer_cast operation.
470     template<typename TFrom>
471     static void doShareCast (Draw_Interpretor& theDI,
472                              const Standard_Integer        theNbIters,
473                              const std::shared_ptr<TFrom>& theSharePtr)
474     {
475       std::vector< std::shared_ptr<typename TTo::element_type> > aSharePointers (theNbIters);
476       {
477         QATimer aTimer (theDI, " ", QATimer::ns, theNbIters);
478         for (Standard_Integer anIter = 0; anIter < theNbIters; ++anIter)
479         {
480           aSharePointers[anIter] = std::dynamic_pointer_cast<typename TTo::element_type, TFrom> (theSharePtr);
481         }
482       }
483     }
484
485   };
486
487   template<typename TAs>
488   static void qaCastAs (Draw_Interpretor& theDI,
489                         const qaclass00_50&    theInst,
490                         const Standard_Integer theNbIters)
491   {
492     #define QA_TEST_CAST10(theTens, theDoCast) \
493       QACast<QA_HANDLE_NAME(theTens ## 0)>::theDoCast(theDI, theNbIters, aPtr); \
494       QACast<QA_HANDLE_NAME(theTens ## 5)>::theDoCast(theDI, theNbIters, aPtr);
495  
496     typedef typename TAs::element_type aPtrType;
497     TAs aDummy (new aPtrType());
498     theDI << "Making a pointer:\n";
499     theDI << aDummy->DynamicType()->Name() << "* ptr = new " << theInst.DynamicType()->Name() << "\n";
500     theDI << "then measuring the time of casting it to base classes from qaclass00_50 to qaclass50_50, ns\n";
501     if (!theInst.IsKind (aDummy->DynamicType()))
502     {
503       return;
504     }
505
506     theDI << "\nOCCT Handle: ";
507     {
508       TAs aPtr ((typename TAs::element_type* )theInst.Clone());
509       QA_TEST_CAST10(0, doDownCast);
510       QA_TEST_CAST10(1, doDownCast);
511       QA_TEST_CAST10(2, doDownCast);
512       QA_TEST_CAST10(3, doDownCast);
513       QA_TEST_CAST10(4, doDownCast);
514       QACast<Handle(qaclass50_50)>::doDownCast(theDI, theNbIters, aPtr);
515     }
516     theDI << "\nC++ dynamic_cast: ";
517     {
518       TAs aPtr ((typename TAs::element_type* )theInst.Clone());
519       QA_TEST_CAST10(0, doDynamicCast);
520       QA_TEST_CAST10(1, doDynamicCast);
521       QA_TEST_CAST10(2, doDynamicCast);
522       QA_TEST_CAST10(3, doDynamicCast);
523       QA_TEST_CAST10(4, doDynamicCast);
524       QACast<Handle(qaclass50_50)>::doDynamicCast(theDI, theNbIters, aPtr);
525     }
526     theDI << "\nC++ dynamic_pointer_cast: ";
527     {
528       std::shared_ptr<typename TAs::element_type> aPtr ((typename TAs::element_type* )theInst.Clone());
529       QA_TEST_CAST10(0, doShareCast);
530       QA_TEST_CAST10(1, doShareCast);
531       QA_TEST_CAST10(2, doShareCast);
532       QA_TEST_CAST10(3, doShareCast);
533       QA_TEST_CAST10(4, doShareCast);
534       QACast<Handle(qaclass50_50)>::doShareCast(theDI, theNbIters, aPtr);
535     }
536   }
537
538 }
539
540 //=======================================================================
541 //function : QAHandleCast
542 //purpose  : Estimate performance of RTTI mechanisms - dynamic type casting
543 //=======================================================================
544 static Standard_Integer QAHandleCast (Draw_Interpretor& theDI,
545                                       Standard_Integer  theArgNb,
546                                       const char**      theArgVec)
547 {
548   if (theArgNb > 4)
549   {
550     std::cout << "Error: wrong syntax! See usage:\n";
551     theDI.PrintHelp (theArgVec[0]);
552     return 1;
553   }
554   Standard_Integer anArgIter = 0;
555   const Standard_Integer anInst   = (++anArgIter < theArgNb) ? Draw::Atoi (theArgVec[anArgIter]) : 50;
556   const Standard_Integer aPtrTo   = (++anArgIter < theArgNb) ? Draw::Atoi (theArgVec[anArgIter]) : 0;
557   const Standard_Integer aNbIters = (++anArgIter < theArgNb) ? Draw::Atoi (theArgVec[anArgIter]) : 1000000;
558
559   if (aNbIters < 1)
560   {
561     std::cout << "Error: number of iterations (" << aNbIters << ") should be positive!\n";
562     return 1;
563   }
564   if (anInst > 50 || anInst < 0)
565   {
566     std::cout << "Error: class instance (" << anInst << ") should be specified within 0..50 range!\n";
567     return 1;
568   }
569   if (aPtrTo > anInst || aPtrTo < 0)
570   {
571     std::cout << "Error: class pointer (" << aPtrTo << ") should be specified within 0.." << anInst << " range!\n";
572     return 1;
573   }
574   else if (aPtrTo % 10 != 0)
575   {
576     std::cout << "Error: class pointer (" << aPtrTo << ") should be multiple of 10!\n";
577     return 1;
578   }
579
580   Handle(qaclass00_50) aHandle  = new qaclass50_50();
581   for (Standard_Integer anInstIter = 50 - anInst; anInstIter > 0; --anInstIter)
582   {
583     Handle(Standard_Transient) aParent (aHandle->CreateParent());
584     aHandle = Handle(qaclass00_50)::DownCast (aParent);
585   }
586
587   std::ios::fmtflags aFlags = std::cout.flags();
588   std::cout.precision (5);
589
590   switch (aPtrTo)
591   {
592     // vc11 requires /bigobj option
593     case 0:  qaCastAs<Handle(qaclass00_50)>(theDI, *aHandle, aNbIters); break;
594     case 10: qaCastAs<Handle(qaclass10_50)>(theDI, *aHandle, aNbIters); break;
595     case 20: qaCastAs<Handle(qaclass20_50)>(theDI, *aHandle, aNbIters); break;
596     case 30: qaCastAs<Handle(qaclass30_50)>(theDI, *aHandle, aNbIters); break;
597     case 40: qaCastAs<Handle(qaclass40_50)>(theDI, *aHandle, aNbIters); break;
598     case 50: qaCastAs<Handle(qaclass50_50)>(theDI, *aHandle, aNbIters); break;
599   }
600   std::cout.setf (aFlags);
601   return 0;
602 }
603
604 //=======================================================================
605 //function : QAHandleKind
606 //purpose  :
607 //=======================================================================
608 static Standard_Integer QAHandleKind (Draw_Interpretor& /*theDI*/,
609                                       Standard_Integer  /*theArgNb*/,
610                                       const char**      /*theArgVec*/)
611 {
612   Handle(Standard_Type) aType00 = STANDARD_TYPE(qaclass00_50);
613   Handle(Standard_Type) aType10 = STANDARD_TYPE(qaclass10_50);
614   Handle(Standard_Type) aType20 = STANDARD_TYPE(qaclass20_50);
615   Handle(Standard_Type) aType30 = STANDARD_TYPE(qaclass30_50);
616   Handle(Standard_Type) aType40 = STANDARD_TYPE(qaclass40_50);
617   Handle(Standard_Type) aType50 = STANDARD_TYPE(qaclass50_50);
618
619   Handle(qaclass00_50) aHandle = new qaclass40_50();
620
621   #define QA_CHECK(theDesc, theExpr, theValue) \
622     {\
623       const bool isTrue = !!(theExpr); \
624       std::cout << theDesc << (isTrue ? " TRUE  " : " FALSE ") << (isTrue == theValue ? " is OK\n" : " is Error\n"); \
625     }
626
627   std::cout << "Check instance of " << aHandle->DynamicType()->Name() << "\n";
628   for (Handle(Standard_Type) aType = aHandle->DynamicType(); ! aType.IsNull(); aType = aType->Parent())
629   {
630     std::cout << " - " << aType->Name() << "\n";
631   }
632
633   QA_CHECK ("Name == qaclass40_50       : ", TCollection_AsciiString("qaclass40_50") == aHandle->DynamicType()->Name(), true);
634
635   QA_CHECK ("IsKind     (aType00)       : ", aHandle->IsKind (aType00), true);
636   QA_CHECK ("IsKind     (aType10)       : ", aHandle->IsKind (aType10), true);
637   QA_CHECK ("IsKind     (aType20)       : ", aHandle->IsKind (aType20), true);
638   QA_CHECK ("IsKind     (aType30)       : ", aHandle->IsKind (aType30), true);
639   QA_CHECK ("IsKind     (aType40)       : ", aHandle->IsKind (aType40), true);
640   QA_CHECK ("IsKind     (aType50)       : ", aHandle->IsKind (aType50), false);
641
642   QA_CHECK ("IsKind     (\"qaclass00_50\"): ", aHandle->IsKind ("qaclass00_50"), true);
643   QA_CHECK ("IsKind     (\"qaclass10_50\"): ", aHandle->IsKind ("qaclass10_50"), true);
644   QA_CHECK ("IsKind     (\"qaclass20_50\"): ", aHandle->IsKind ("qaclass20_50"), true);
645   QA_CHECK ("IsKind     (\"qaclass30_50\"): ", aHandle->IsKind ("qaclass30_50"), true);
646   QA_CHECK ("IsKind     (\"qaclass40_50\"): ", aHandle->IsKind ("qaclass40_50"), true);
647   QA_CHECK ("IsKind     (\"qaclass50_50\"): ", aHandle->IsKind ("qaclass50_50"), false);
648
649   QA_CHECK ("IsInstance (aType00)       : ", aHandle->IsInstance (aType00), false);
650   QA_CHECK ("IsInstance (aType10)       : ", aHandle->IsInstance (aType10), false);
651   QA_CHECK ("IsInstance (aType20)       : ", aHandle->IsInstance (aType20), false);
652   QA_CHECK ("IsInstance (aType30)       : ", aHandle->IsInstance (aType30), false);
653   QA_CHECK ("IsInstance (aType40)       : ", aHandle->IsInstance (aType40), true);
654   QA_CHECK ("IsInstance (aType50)       : ", aHandle->IsInstance (aType50), false);
655
656 #ifdef HAVE_CPP11
657   std::cout << "\nC++11:\n";
658   std::type_index aCppType     = typeid(*aHandle.operator->());
659   std::cout << "typeid().name()    = '" << typeid(*aHandle.operator->()).name()     << "'\n";
660 #ifdef _MSC_VER
661   std::cout << "typeid().raw_name()= '" << typeid(*aHandle.operator->()).raw_name() << "'\n";
662 #endif
663
664   std::cout << "[ANON]typeid().name()    = '" << typeid(qaclass50_50ANON).name()     << "'\n";
665 #ifdef _MSC_VER
666   std::cout << "[ANON]typeid().raw_name()= '" << typeid(qaclass50_50ANON).raw_name() << "'\n";
667 #endif
668
669   std::cout << "[NS]typeid().name()    = '" << typeid(QaNamespace::qaclass50_50).name()     << "'\n";
670 #ifdef _MSC_VER
671   std::cout << "[NS]typeid().raw_name()= '" << typeid(QaNamespace::qaclass50_50).raw_name() << "'\n";
672 #endif
673
674   QA_CHECK ("is typeid  (aType00)       : ", typeid(*aHandle.operator->()) == typeid(qaclass00_50), false);
675   QA_CHECK ("is typeid  (aType10)       : ", typeid(*aHandle.operator->()) == typeid(qaclass10_50), false);
676   QA_CHECK ("is typeid  (aType20)       : ", typeid(*aHandle.operator->()) == typeid(qaclass20_50), false);
677   QA_CHECK ("is typeid  (aType30)       : ", typeid(*aHandle.operator->()) == typeid(qaclass30_50), false);
678   QA_CHECK ("is typeid  (aType40)       : ", typeid(*aHandle.operator->()) == typeid(qaclass40_50), true);
679   QA_CHECK ("is typeid  (aType50)       : ", typeid(*aHandle.operator->()) == typeid(qaclass50_50), false);
680
681   QA_CHECK ("is type_index (aType00)    : ", aCppType == typeid(qaclass00_50), false);
682   QA_CHECK ("is type_index (aType40)    : ", aCppType == typeid(qaclass40_50), true);
683
684   QA_CHECK ("IsClass(Standard_Transient): ", std::is_class<Standard_Transient>::value == !!STANDARD_TYPE(Standard_Transient)->IsClass(), true);
685   //QA_CHECK ("IsEnum (Message_Status)    : ", std::is_enum<Message_Status>::value == !!STANDARD_TYPE(Message_Status)->IsEnumeration(), true);
686 #endif
687
688   return 0;
689 }
690
691 void QANCollection::CommandsHandle (Draw_Interpretor& theCommands)
692 {
693   const char* THE_GROUP = "QANCollection";
694   theCommands.Add ("QAHandleBool",
695                    "Test handle boolean operator",
696                    __FILE__, QAHandleBool, THE_GROUP);
697   theCommands.Add ("QAHandleInc",
698                    "QAHandleInc nbIter=1000000"
699                    "\n\t\t: Test handle increment performance",
700                    __FILE__, QAHandleInc,  THE_GROUP);
701   theCommands.Add ("QAHandleCast",
702                    "QAHandleCast [instance=50 [pointerTo=0 [nbIter=1000000]]]"
703                    "\n\t\t: Test handle DownCast performance."
704                    "\n\t\t: instance  - specifies the depth of instantiated class"
705                    "\n\t\t: pointerTo - specifies the depth of pointer class, where instance is stored into",
706                    __FILE__, QAHandleCast, THE_GROUP);
707   theCommands.Add ("QAHandleKind",
708                    "Test handle IsKind",
709                    __FILE__, QAHandleKind, THE_GROUP);
710   theCommands.Add ("QAHandleOps",
711                    "Test handle operations",
712                    __FILE__, QAHandleOps, THE_GROUP);
713   return;
714 }