]> Creatis software - bbtk.git/blob - kernel/src/bbtkConnection.cxx
0b8fb9c11dc890b0ee3ffe9b5a24d491a9828e07
[bbtk.git] / kernel / src / bbtkConnection.cxx
1 /*=========================================================================                                                                               
2   Program:   bbtk
3   Module:    $RCSfile: bbtkConnection.cxx,v $
4   Language:  C++
5   Date:      $Date: 2008/10/17 08:18:13 $
6   Version:   $Revision: 1.15 $
7 =========================================================================*/
8
9 /* ---------------------------------------------------------------------
10
11 * Copyright (c) CREATIS-LRMN (Centre de Recherche en Imagerie Medicale)
12 * Authors : Eduardo Davila, Laurent Guigues, Jean-Pierre Roux
13 *
14 *  This software is governed by the CeCILL-B license under French law and 
15 *  abiding by the rules of distribution of free software. You can  use, 
16 *  modify and/ or redistribute the software under the terms of the CeCILL-B 
17 *  license as circulated by CEA, CNRS and INRIA at the following URL 
18 *  http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html 
19 *  or in the file LICENSE.txt.
20 *
21 *  As a counterpart to the access to the source code and  rights to copy,
22 *  modify and redistribute granted by the license, users are provided only
23 *  with a limited warranty  and the software's author,  the holder of the
24 *  economic rights,  and the successive licensors  have only  limited
25 *  liability. 
26 *
27 *  The fact that you are presently reading this means that you have had
28 *  knowledge of the CeCILL-B license and that you accept its terms.
29 * ------------------------------------------------------------------------ */                                                                         
30
31 /**
32  *\file
33  *\brief Class bbtk::Connection
34  */
35
36 #include "bbtkConnection.h"
37 #include "bbtkFactory.h"
38 #include "bbtkBlackBox.h"
39 #include "bbtkMessageManager.h"
40
41 namespace bbtk
42 {
43   //==================================================================
44   Connection::Pointer Connection::New(BlackBox::Pointer from, 
45                                       const std::string& output,
46                                       BlackBox::Pointer to, 
47                                       const std::string& input ,
48                                       const Factory::Pointer f  )
49   {
50     bbtkDebugMessage("object",1,"##> Connection::Connection(\""
51                      <<from->bbGetName()<<"\",\""<<output<<"\",\""
52                      <<to->bbGetName()<<"\",\""<<input<<"\")"
53                      <<std::endl);
54     Connection::Pointer p = 
55       MakePointer(new Connection(from,output,to,input,f));
56     bbtkDebugMessage("object",1,"<## Connection::Connection(\""
57                      <<from->bbGetName()<<"\",\""<<output<<"\",\""
58                      <<to->bbGetName()<<"\",\""<<input<<"\")"
59                      <<std::endl);
60     return p;
61   }
62   //==================================================================
63
64   //==================================================================
65   /// Ctor with the black box from and to and their input and output.
66 /// Check the input and output compatibility
67 Connection::Connection(BlackBox::Pointer from, const std::string& output,
68                        BlackBox::Pointer to, const std::string& input ,
69                        const Factory::Pointer f  )
70     : mAdaptor(),
71       mFactory(f),
72       mFromAny(false),
73       mToAny(false)
74   {
75     bbtkDebugMessage("object",2,"==> Connection::Connection(\""
76                      <<from->bbGetName()<<"\",\""<<output<<"\",\""
77                      <<to->bbGetName()<<"\",\""<<input<<"\")"
78                      <<std::endl);    
79
80     bbtkDebugMessage("connection",1,"==> Connection::Connection(\""
81                      <<from->bbGetFullName()<<"\",\""<<output<<"\",\""
82                      <<to->bbGetFullName()<<"\",\""<<input<<"\")"
83                      <<std::endl);    
84
85     
86
87     if (! from->bbHasOutput(output) )
88       {
89         bbtkError("The box \""<<from->bbGetTypeName()<<
90                   "\" has no output \""<<output<<"\"");
91       }
92     if (! to->bbHasInput(input) )
93       {
94         bbtkError("The box \""<<to->bbGetTypeName()<<
95                   "\" has no input \""<<input<<"\"");
96       } 
97
98     if (to->bbGetInputConnectorMap().find(input)->second->IsConnected())
99       {
100         bbtkError("The input \""<<input<<"\" of the box \""<<to->bbGetName()
101                   <<"\" is already connected");
102       }
103     
104     //  std::string t1 ( from->bbGetOutputType(output).name() );
105     //   std::string t2 ( to->bbGetInputType(input).name() );
106     // if  //( t1 != t2 ) 
107     if ( from->bbGetOutputType(output) !=
108          to->bbGetInputType(input) )
109       {
110         if ( from->bbGetOutputType(output) == typeid(Data) )
111           {
112             bbtkWarning("Connection '"
113                         <<GetFullName()
114                         <<"' : '"<<from->bbGetName()<<"."<<output
115                         <<"' is of type <"
116                         <<HumanTypeName<Data>()
117                         <<"> : type compatibility with '"
118                         <<to->bbGetName()<<"."<<input
119                         <<"' will be resolved at run time"
120                         );
121             mFromAny = true;
122           }
123         else if (  to->bbGetInputType(input) == typeid(Data) )
124           {   
125             bbtkDebugMessage("Kernel",8," -> '"<<input<<"' type is "
126                              <<TypeName<Data>()<<" : can receive any data"
127                              <<std::endl);
128             mToAny = true;
129           }
130         else 
131           {
132             //   std::cout << "Adaptive connection "<<std::endl;
133             std::string name;
134             name = from->bbGetName() + "." + output + "-" 
135               + to->bbGetName() + "." + input; 
136             mAdaptor = mFactory.lock()
137               ->NewAdaptor(from->bbGetOutputType(output),
138                            to->bbGetInputType(input),
139                            name);
140             if (!mAdaptor)  
141               {  
142                 bbtkError("did not find any <"
143                           <<TypeName(from->bbGetOutputType(output))
144                           <<"> to <"
145                           <<TypeName(to->bbGetInputType(input))
146                           <<"> adaptor");
147               } 
148           }
149       }
150
151
152     mFrom = from;
153     mOriginalFrom = from;
154     mTo = to;
155     mOriginalTo = to;
156     mInput = mOriginalInput = input;
157     mOutput = mOriginalOutput = output;
158
159      // Lock this pointer !!!
160     //Pointer p = MakePointer(this,true);
161     from->bbConnectOutput(output,this);
162     to->bbConnectInput(input,this);
163
164     
165     bbtkDebugMessage("connection",1,"<== Connection::Connection(\""
166                      <<from->bbGetFullName()<<"\",\""<<output<<"\",\""
167                      <<to->bbGetFullName()<<"\",\""<<input<<"\")"
168                      <<std::endl);    
169
170     bbtkDebugMessage("object",2,"==> Connection::Connection(\""
171                      <<from->bbGetName()<<"\",\""<<output<<"\",\""
172                      <<to->bbGetName()<<"\",\""<<input<<"\")"
173                      <<std::endl);    
174   }
175  //==================================================================
176  
177   //==================================================================
178   Connection::Pointer Connection::New(BlackBox::Pointer from, 
179                                       const std::string& output,
180                                       BlackBox::Pointer to, 
181                                       const std::string& input )
182   {
183     bbtkDebugMessage("object",1,"##> Connection::Connection(\""
184                      <<from->bbGetName()<<"\",\""<<output<<"\",\""
185                      <<to->bbGetName()<<"\",\""<<input<<"\")"
186                      <<std::endl);
187     Connection::Pointer p = 
188       MakePointer(new Connection(from,output,to,input));
189     bbtkDebugMessage("object",1,"<## Connection::Connection(\""
190                      <<from->bbGetName()<<"\",\""<<output<<"\",\""
191                      <<to->bbGetName()<<"\",\""<<input<<"\")"
192                      <<std::endl);
193     return p;
194   }
195   //==================================================================
196
197   //==================================================================
198   /// Ctor with the black box from and to and their input and output.
199 /// Check the input and output compatibility
200 Connection::Connection(BlackBox::Pointer from, const std::string& output,
201                        BlackBox::Pointer to, const std::string& input )
202   : mAdaptor(),
203       mFactory(),
204       mFromAny(false),
205       mToAny(false)
206   {
207     bbtkDebugMessage("object",2,"==> Connection::Connection(\""
208                      <<from->bbGetName()<<"\",\""<<output<<"\",\""
209                      <<to->bbGetName()<<"\",\""<<input<<"\")"
210                      <<std::endl);    
211
212     bbtkDebugMessage("connection",1,"==> Connection::Connection(\""
213                      <<from->bbGetFullName()<<"\",\""<<output<<"\",\""
214                      <<to->bbGetFullName()<<"\",\""<<input<<"\")"
215                      <<std::endl);    
216
217     
218
219     if (! from->bbHasOutput(output) )
220       {
221         bbtkError("The box \""<<from->bbGetTypeName()<<
222                   "\" has no output \""<<output<<"\"");
223       }
224     if (! to->bbHasInput(input) )
225       {
226         bbtkError("The box \""<<to->bbGetTypeName()<<
227                   "\" has no input \""<<input<<"\"");
228       } 
229
230     if (to->bbGetInputConnectorMap().find(input)->second->IsConnected())
231       {
232         bbtkError("The input \""<<input<<"\" of the box \""<<to->bbGetName()
233                   <<"\" is already connected");
234       }
235     
236     //  std::string t1 ( from->bbGetOutputType(output).name() );
237     //   std::string t2 ( to->bbGetInputType(input).name() );
238     // if  //( t1 != t2 ) 
239     if ( from->bbGetOutputType(output) !=
240          to->bbGetInputType(input) )
241       {
242         if ( from->bbGetOutputType(output) == typeid(Data) )
243           {
244             bbtkWarning("Connection '"
245                         <<GetFullName()
246                         <<"' : '"<<from->bbGetName()<<"."<<output
247                         <<"' is of type <"
248                         <<HumanTypeName<Data>()
249                         <<"> : type compatibility with '"
250                         <<to->bbGetName()<<"."<<input
251                         <<"' will be resolved at run time"
252                         );
253             mFromAny = true;
254           }
255         else if (  to->bbGetInputType(input) == typeid(Data) )
256           {   
257             bbtkDebugMessage("Kernel",8," -> '"<<input<<"' type is "
258                              <<TypeName<Data>()<<" : can receive any data"
259                              <<std::endl);
260             mToAny = true;
261           }
262         else 
263           {
264             bbtkError("Connection created between different types without Factory provided");
265           }
266       }
267
268
269     mFrom = from;
270     mOriginalFrom = from;
271     mTo = to;
272     mOriginalTo = to;
273     mInput = mOriginalInput = input;
274     mOutput = mOriginalOutput = output;
275
276      // Lock this pointer !!!
277     //Pointer p = MakePointer(this,true);
278     from->bbConnectOutput(output,this);
279     to->bbConnectInput(input,this);
280
281     
282     bbtkDebugMessage("connection",1,"<== Connection::Connection(\""
283                      <<from->bbGetFullName()<<"\",\""<<output<<"\",\""
284                      <<to->bbGetFullName()<<"\",\""<<input<<"\")"
285                      <<std::endl);    
286
287     bbtkDebugMessage("object",2,"==> Connection::Connection(\""
288                      <<from->bbGetName()<<"\",\""<<output<<"\",\""
289                      <<to->bbGetName()<<"\",\""<<input<<"\")"
290                      <<std::endl);    
291   }
292  //==================================================================
293  
294   //==================================================================
295   /// Dtor 
296   Connection::~Connection()
297   {
298     bbtkDebugMessage("object",2,
299                      "==> Connection::~Connection() ["
300                      <<GetFullName()<<"]"<<std::endl);
301
302     if (mAdaptor) mAdaptor.reset();
303     if (mFrom!=0) 
304       {
305         mFrom->bbDisconnectOutput(mOutput,this);
306         //                                GetThisPointer<Connection>());
307         mFrom.reset();
308       }
309     else 
310       {
311         bbtkInternalError("Connection::~Connection() : invalid initial box pointer");
312       }
313     if (mTo!=0) 
314       {
315         mTo->bbDisconnectInput(mInput,this);//   GetThisPointer<Connection>());
316         mTo.reset();
317       }
318     else 
319       {
320         bbtkInternalError("Connection::~Connection() : invalid final box pointer");
321       }
322
323
324     bbtkDebugMessage("object",2,
325                      "<== Connection::~Connection() ["
326                      <<GetFullName()<<"]"<<std::endl);
327   }
328   //==================================================================
329   
330   //==================================================================
331   /// Backward Update
332   IOStatus Connection::BackwardUpdate()
333   {
334     bbtkDebugMessage("process",5,
335                      "===> Connection::BackwardUpdate() ["
336                      <<GetFullName()<<"]"<<std::endl);
337
338     IOStatus s = UPTODATE;
339     s = mFrom->bbBackwardUpdate(GetThisPointer<Connection>());
340
341     TransferData();
342
343     if (mAdaptor && (s==MODIFIED)) mAdaptor->bbSetModifiedStatus();
344
345     bbtkDebugMessage("process",5,
346                      "<=== Connection::BackwardUpdate() ["
347                      <<GetFullName()<<"]"<<std::endl);
348     return s;
349   }
350   //==================================================================
351
352   /*
353   //==================================================================
354   /// Forward Update
355   void Connection::ForwardUpdate()
356   {
357     bbtkDebugMessageInc("process",2,
358                         "Connection::ForwardUpdate() ["
359                         <<GetFullName()<<"]"<<std::endl);
360
361   
362     TransferData();
363
364     mTo->bbForwardUpdate(this);
365
366     bbtkDebugDecTab("process",2);
367   }
368   //==================================================================
369   */
370
371   //==================================================================
372   /// Transfers the data from the source output to the target input
373   /// doing necessary conversions (adaptation or pointer cast)
374   void Connection::TransferData()
375   {
376     bbtkDebugMessageInc("data",3,
377                         "Connection::TransferData() ["
378                         <<GetFullName()<<"]"<<std::endl);
379     
380     
381     // If an adaptor was created we need to adapt the data
382     if (mAdaptor) 
383       {
384         mAdaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
385         mAdaptor->bbExecute();
386         // LG : Connection Update does not set mTo as modified
387         mTo->bbSetInput(mInput, mAdaptor->bbGetOutput("Out"),false);
388         
389       }
390     // If no adaptor but source type is an any and target is not an any
391     else if ( mFromAny && (! mToAny) )
392       {
393         bbtkDebugMessage("data",3,
394                          " * Source type is an "
395                          <<HumanTypeName<Data>()
396                          <<" which contains a <"
397                          <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
398                          <<">"<<std::endl);
399         bbtkDebugMessage("data",3,
400                          " * Target type is <"
401                          <<HumanTypeName(mTo->bbGetInputType(mInput))
402                          <<">"<<std::endl);
403         
404         // 1) Test strict type matching between any content and target
405         if (mFrom->bbGetOutput(mOutput)
406             .contains( mTo->bbGetInputType(mInput) ) )
407           {
408             bbtkDebugMessage("data",3,
409                              " -> Equal types : transfer ok"<<std::endl);
410             mTo->bbSetInput( mInput, 
411                              mFrom->bbGetOutput(mOutput),
412                              false);
413           }
414         else 
415           {
416             // 2) Look for an adaptor
417             bbtk::BlackBox::Pointer adaptor;
418             try 
419               {
420                 adaptor = mFactory.lock()
421                   ->NewAdaptor(mFrom->bbGetOutput(mOutput).type(),
422                                mTo->bbGetInputType(mInput),
423                                "");
424               }
425             catch (...)
426               {
427               }
428             if (adaptor)  
429               {
430                 bbtkDebugMessage("data",3," -> Adaptor found : using it"
431                                  <<std::endl);
432                   adaptor->bbSetInput("In",mFrom->bbGetOutput(mOutput),false);
433                 adaptor->bbExecute();
434                 // LG : Connection Update does not set mTo as modified
435                 mTo->bbSetInput(mInput, adaptor->bbGetOutput("Out"),false);
436                 //      adaptor->bbDelete();
437               }
438             // 3) If no adaptor found but the any content is a pointer
439             //    and target type is also a pointer : we try run-time cast
440             else if ( (mFrom->bbGetOutput(mOutput).contains_pointer()) &&
441                       (mTo->bbGetDescriptor()->GetInputDescriptor(mInput)
442                        ->IsPointerType()) )
443               {
444                 bbtkDebugMessage("data",3,
445                                  " -> No adaptor found but source and target types are both pointers : trying up or down cast"<<std::endl);
446                 
447                 void* nptr = 
448                   mFrom->bbGetOutput(mOutput)
449                   .get_pointer_to(mTo->bbGetInput(mInput).pointed_type());
450                 if (!nptr)  
451                   {
452                     bbtkError("Connection '"
453                               <<GetFullName()
454                               <<"' : <"
455                               <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
456                               <<"> to <"
457                               <<HumanTypeName(mTo->bbGetInputType(mInput))
458                               <<"> : no adaptor available and run-time up and down cast failed");
459                   }
460                 mTo->bbBruteForceSetInputPointer(mInput, nptr, false);
461               }
462             // 4) Nothing worked : error
463             else 
464               {
465                 bbtkError("Connection '"<<GetFullName()<<"' "
466                           <<"no adaptor found to convert <"
467                           <<HumanTypeName(mFrom->bbGetOutput(mOutput).type())
468                           <<"> to <"
469                           <<HumanTypeName(mTo->bbGetInputType(mInput))<<">");
470               }
471           }
472       }
473     // EO : mFromAny && ! mToAny
474     // Default case : types are the same; we use simple get-set
475     else 
476       {
477         // LG : Connection Update does not set mTo as modified
478         mTo->bbSetInput(mInput, mFrom->bbGetOutput(mOutput),false);
479       }
480
481   }
482   //==================================================================
483   
484   //==================================================================
485   /// Modified
486   void Connection::SetModifiedStatus()
487   {
488     bbtkDebugMessage("modified",2,
489                      "==> Connection::SetModifiedStatus() ["
490                      <<GetFullName()<<"]"<<std::endl);
491     
492     if (mAdaptor) mAdaptor->bbSetModifiedStatus();
493     
494     mTo->bbSetModifiedStatus(  mTo->bbGetInputConnectorMap().find(mInput)->second );
495     
496     /*
497     bbtkDebugMessage("modified",2,
498                      "==> Connection::SetModifiedStatus() ["
499                      <<GetFullName()<<"]"<<std::endl);
500     */
501   }
502   //==================================================================
503
504   
505   //==================================================================
506   std::string Connection::GetFullName() const {
507     if (mFrom && mTo) 
508       {
509         std::string res = mFrom->bbGetName()+"."+mOutput+"--"
510           +mTo->bbGetName()+"."+mInput;
511         if ((!mOriginalFrom.expired()) && (!mOriginalTo.expired()) &&
512             ((mFrom!=mOriginalFrom.lock())||(mTo!=mOriginalTo.lock())))
513           {
514             res += "("+mOriginalFrom.lock()->bbGetName()
515               +"."+mOriginalOutput+"--"
516               + mOriginalTo.lock()->bbGetName()+"."+mOriginalInput+")";
517           }
518         return res;
519       }
520     return "***Invalid Connection***";
521   }
522   //==================================================================
523
524   //==================================================================
525   void Connection::Check() const
526   {
527     bbtkMessage("debug",1,"** Checking Connection "<<(void*)this<<" ["<<GetFullName()<<"]"
528                 <<std::endl);
529     if (mFrom==0) 
530       {
531         bbtkMessage("debug",2," - From = 0"<<std::endl);
532       }
533     else
534       {
535         bbtkMessage("debug",2," - From : "<<mFrom->bbGetFullName()<<std::endl);
536         if (!mFrom->bbHasOutput(mOutput))
537           {
538             bbtkError("** Checking Connection "<<(void*)this
539                        <<" ["<<GetFullName()<<"] : "
540                       << mFrom->bbGetFullName()<<" does not have output '"
541                       <<mOutput<<"'");
542           }     
543         bbtkMessage("debug",2," - From : Output '"<<mOutput<<"' exists"<<std::endl);
544         BlackBox::OutputConnectorMapType::const_iterator i 
545           = mFrom->bbGetOutputConnectorMap().find(mOutput);
546         if (i== mFrom->bbGetOutputConnectorMap().end())
547           {
548              bbtkError("** Checking Connection "<<(void*)this
549                        <<" ["<<GetFullName()<<"] : "
550                        <<mFrom->bbGetFullName()<<" output '"
551                        <<mOutput<<"' is not in OutputConnectorMap");
552           }
553         bbtkMessage("debug",2," - From : Output '"<<mOutput
554                     <<"' is in OutputConnectorMap"<<std::endl);
555
556         std::vector< Connection* >::const_iterator j;
557         /*
558         for (j  = i->second->GetConnectionVector().begin();
559              j != i->second->GetConnectionVector().end();
560              ++j)
561           {
562             if ((*j)==this) break;
563           }
564         */
565         j = find(i->second->GetConnectionVector().begin(),
566                  i->second->GetConnectionVector().end(),
567                  this);
568        
569         if (j==i->second->GetConnectionVector().end())
570           {
571             bbtkError("** Checking Connection "<<(void*)this
572                       <<" ["<<GetFullName()<<"] : "
573                       << "Connection ["<<GetFullName()<<"] : "
574                       <<" OutputConnector '"
575                       <<mOutput<<"' of "<<mFrom->bbGetFullName()
576                       <<" does not point to this connection");
577             
578           }
579         bbtkMessage("debug",2," - From : This connection is in OutputConnector connection vector"<<std::endl);
580         bbtkMessage("debug",2," * Box from : Check successfull"<<std::endl);
581
582       }
583
584     if (mTo==0) 
585       {
586         bbtkMessage("debug",2," - To   = 0"<<std::endl);
587       }
588     else
589       {
590         bbtkMessage("debug",2," - To   : "<<mTo->bbGetName()<<std::endl);
591         //      std::cout << mTo << std::endl;
592         //      std::cout << mTo->bbGetDescriptor() << std::endl;
593         //      std::cout << mTo->bbGetDescriptor()->GetTypeName() << std::endl;
594         //      mTo->bbGetFullName();
595         bbtkMessage("debug",2," - To   : "<<mTo->bbGetFullName()<<std::endl);
596         if (!mTo->bbHasInput(mInput))
597           {
598             bbtkError("** Checking Connection "<<(void*)this
599                       <<" ["<<GetFullName()<<"] : "
600                       <<mTo->bbGetFullName()<<" does not have input '"
601                       <<mInput<<"'");
602           }     
603         bbtkMessage("debug",2," - To   : Input '"<<mInput<<"' exists"<<std::endl);
604         BlackBox::InputConnectorMapType::const_iterator i 
605           = mTo->bbGetInputConnectorMap().find(mInput);
606         if (i== mTo->bbGetInputConnectorMap().end())
607           {
608              bbtkError("** Checking Connection "<<(void*)this
609                        <<" ["<<GetFullName()<<"] : "
610                        <<mTo->bbGetFullName()<<" input '"
611                        <<mInput<<"' is not in InputConnectorMap");
612           }
613         bbtkMessage("debug",2," - To   : Input '"<<mInput
614                     <<"' is in InputConnectorMap"<<std::endl);
615
616         if (i->second->GetConnection()==0)
617           {
618             bbtkError("** Checking Connection "<<(void*)this
619                       <<" ["<<GetFullName()<<"] : "
620                       <<"Connection "<<GetFullName()<<" : "
621                       <<" InputConnector '"
622                       <<mInput<<"' of "<<mTo->bbGetFullName()
623                       <<" does not point to this connection");
624     
625           }
626         bbtkMessage("debug",2," - To   : This connection is in InputConnector connection vector"<<std::endl);
627         bbtkMessage("debug",2," * Box to   : Check successfull"<<std::endl);
628
629       }
630   }
631   //==================================================================
632  //==========================================================================
633   std::string Connection::GetObjectName() const
634   {
635     std::string s("Connection '");
636     s += GetFullName();
637     s += "'";
638     return s;
639   }
640   //==========================================================================
641   
642   //==========================================================================
643   std::string  Connection::GetObjectInfo() const 
644   {
645     std::stringstream i;
646     return i.str();
647   }
648   //==========================================================================
649
650  //==========================================================================
651 size_t  Connection::GetObjectSize() const 
652 {
653   size_t s = Superclass::GetObjectSize();
654   s += Connection::GetObjectInternalSize();
655   return s;
656   }
657   //==========================================================================
658   //==========================================================================
659 size_t  Connection::GetObjectInternalSize() const 
660 {
661   size_t s = sizeof(Connection);
662   return s;
663   }
664   //==========================================================================
665   //==========================================================================
666   size_t  Connection::GetObjectRecursiveSize() const 
667   {
668     size_t s = Superclass::GetObjectRecursiveSize();
669     s += Connection::GetObjectInternalSize();
670     return s;
671   }
672   //==========================================================================
673
674 }// namespace bbtk
675
676
677
678
679