]> SALOME platform Git repositories - modules/yacs.git/blob - src/engine/TypeCode.cxx
Salome HOME
mergefrom branch BR_V511_PR tag mergeto_trunk_03feb09
[modules/yacs.git] / src / engine / TypeCode.cxx
1 //  Copyright (C) 2006-2008  CEA/DEN, EDF R&D
2 //
3 //  This library is free software; you can redistribute it and/or
4 //  modify it under the terms of the GNU Lesser General Public
5 //  License as published by the Free Software Foundation; either
6 //  version 2.1 of the License.
7 //
8 //  This library is distributed in the hope that it will be useful,
9 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 //  Lesser General Public License for more details.
12 //
13 //  You should have received a copy of the GNU Lesser General Public
14 //  License along with this library; if not, write to the Free Software
15 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 //  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 #include "TypeCode.hxx"
20 #include <sstream>
21 #include <iostream>
22 #include <cstring>
23
24 //#define _DEVDEBUG_
25 #include "YacsTrace.hxx"
26
27 using namespace YACS::ENGINE;
28 using namespace std;
29
30 const char *TypeCode::KIND_STR_REPR []={ "None", "double", "int", "string", "bool", "Objref", "Sequence", "Array","Struct" };
31
32 // --- TypeCode
33
34 TypeCode::TypeCode(DynType kind):_kind(kind)
35 {
36 }
37
38 TypeCode::TypeCode(const TypeCode& tc):_kind(tc._kind)
39 {
40 }
41
42 TypeCode::~TypeCode()
43 {
44 }
45
46 DynType TypeCode::kind() const
47 {
48   return _kind;
49 }
50
51 TypeCode *TypeCode::clone() const
52 {
53   return new TypeCode(*this);
54 }
55
56 void TypeCode::putReprAtPlace(char *pt, const char *val, bool deepCpy) const
57 {
58   AtomAny::putReprAtPlace(pt,val,this,deepCpy);
59 }
60
61 void TypeCode::destroyZippedAny(char *data) const
62 {
63   AtomAny::destroyReprAtPlace(data,this);
64 }
65
66 AnyPtr TypeCode::getOrBuildAnyFromZippedData(char *data) const
67 {
68   return AtomAny::getOrBuildFromData(data,this);
69 }
70
71 const char * TypeCode::name() const throw(Exception)
72 {
73   //throw Exception("No name");
74   return id();
75 }
76
77 const char * TypeCode::shortName() const
78 {
79   //throw Exception("No shortName");
80   return id();
81 }
82
83 const char * TypeCode::id() const throw(Exception)
84 {
85   switch(_kind)
86     {
87     case Double:
88       return "double";
89     case Int:
90       return "int";
91     case String:
92       return "string";
93     case Bool:
94       return "bool";
95     default:
96       return "";
97     }
98 }
99
100 int TypeCode::isA(const char* id) const throw(Exception)
101 {
102   throw Exception("Not implemented for this type");
103 }
104
105 int TypeCode::isA(const TypeCode* tc) const 
106 {
107   if(_kind == tc->kind()) return 1;
108   return 0;
109 }
110
111 //! Check if this TypeCode is adaptable to a given TypeCode (tc)
112 /*!
113  * this TypeCode is adaptable to tc if tc type can be converted to this type
114  *
115  *   \param tc : the TypeCode that must be convertible to this
116  */
117 int TypeCode::isAdaptable(const TypeCode* tc) const
118 {
119   switch(_kind)
120     {
121     case Double:
122       if (tc->kind() == Double) return 1;
123       if (tc->kind() == Int) return 1;
124       return 0;
125     case Int:
126       if (tc->kind() == Int) return 1;
127       return 0;
128     case String:
129       if (tc->kind() == String) return 1;
130       return 0;
131     case Bool:
132       if (tc->kind() == Bool) return 1;
133       if (tc->kind() == Int) return 1;
134       return 0;
135     default:
136       //objref, sequence, ...
137       return 0;
138     }
139 }
140
141 //! Check if this TypeCode can be used in place of tc
142 /*!
143  * this TypeCode is equivalent to tc if they have the same kind
144  *
145  *   \param tc : the TypeCode to compare
146  */
147 int TypeCode::isEquivalent(const TypeCode* tc) const 
148 {
149   if(_kind == tc->kind()) return 1;
150   return 0;
151 }
152
153 unsigned TypeCode::getSizeInByteOfAnyReprInSeq() const
154 {
155   switch(_kind)
156     {
157     case Double:
158       return sizeof(double);
159     case Int:
160       return sizeof(int);
161     case String:
162       return sizeof(StringOnHeap *);
163     case Bool:
164       return sizeof(bool);
165     default:
166       return sizeof(void *);
167     }
168 }
169
170 const TypeCode * TypeCode::contentType() const throw(Exception)
171 {
172   throw Exception("No content type");
173 };
174
175 static inline int validChar0(char c)
176 {
177   return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
178 }
179
180 static inline int validNextChar(char c)
181 {
182   return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
183           (c >= '0' && c <= '9') || (c == '_') || (c == '/'));
184 }
185
186 static void checkValidName(const char* name)
187 {
188   int ok = 1;
189   if (*name) 
190     {
191       if (!validChar0(*name++)) ok = 0;
192       for(; ok && *name; name++) if (!validNextChar(*name)) ok = 0; 
193     }
194   if (!ok)throw YACS::Exception("Invalid Name");
195 }
196
197 const char *TypeCode::getKindRepr(DynType kind)
198 {
199   return KIND_STR_REPR[(int)kind];
200 }
201
202 const char * TypeCode::getKindRepr() const
203 {
204   return KIND_STR_REPR[(int)_kind];
205 }
206
207 //! static factory of object reference type given an id and a name
208 TypeCode * TypeCode::interfaceTc(const char* id,
209                                   const char* name)
210 {
211   checkValidName(name);
212   return new TypeCodeObjref(id, name);
213 };
214
215 //! static factory of object reference type given an id, a name and a list of base types
216 /*!
217  *   \param id :  the id
218  *   \param name :  the name
219  *   \param ltc :  the list of base types
220  *
221  *   The name must be a valid one (throw Exception is not)
222  */
223 TypeCode * TypeCode::interfaceTc(const char* id,
224                                   const char* name,
225                                   const std::list<TypeCodeObjref *>& ltc)
226 {
227   checkValidName(name);
228   return new TypeCodeObjref(id, name,ltc);
229 }
230
231
232 //! static factory of sequence type given an id, a name and a content type
233 TypeCode * TypeCode::sequenceTc(const char* id,
234                                  const char* name,
235                                  TypeCode *content)
236 {
237   std::string typname;
238   if(std::string(name)=="")
239     {
240       typname="seq"+std::string(content->name());
241       name=typname.c_str();
242     }
243   return new TypeCodeSeq(id, name,content);
244 };
245 //! static factory of struct type given an id and a name 
246 TypeCode * TypeCode::structTc(const char* id,
247                                  const char* name)
248 {
249   return new TypeCodeStruct(id, name);
250 };
251
252 TypeCodeComposed::TypeCodeComposed(const TypeCodeComposed& other):TypeCode(other),
253                                                                   _name(other._name),_repoId(other._repoId),
254                                                                   _shortName(other._shortName)
255 {
256 }
257
258 TypeCodeComposed::TypeCodeComposed(DynType kind, const char* repositoryId, const char* name):TypeCode(kind),
259                                                                                              _repoId(repositoryId),_name(name)
260 {
261   string::size_type debut =_name.find_last_of('/');
262   if(debut == std::string::npos)
263     _shortName= name;
264   else
265     _shortName=_name.substr(debut+1);
266 }
267
268 // --- TypeCodeObjref
269
270
271 TypeCodeObjref::TypeCodeObjref(const char* repositoryId, 
272                                const char* name) : TypeCodeComposed(Objref,repositoryId,name)
273 {
274 }
275
276
277 TypeCodeObjref::~TypeCodeObjref()
278 {
279   list<TypeCodeObjref *>::iterator iter;
280   for(iter=_listOfBases.begin();iter != _listOfBases.end(); iter++)
281     (*iter)->decrRef();
282 }
283
284 TypeCode *TypeCodeObjref::clone() const
285 {
286   return new TypeCodeObjref(*this);
287 }
288
289 void TypeCodeObjref::putReprAtPlace(char *pt, const char *val, bool deepCpy) const
290 {
291   throw Exception("Not implemented yet : YACS::Any for objs ref");
292 }
293
294 void TypeCodeObjref::destroyZippedAny(char *data) const
295 {
296   throw Exception("Not implemented yet : YACS::Any for objs ref");
297 }
298
299 AnyPtr TypeCodeObjref::getOrBuildAnyFromZippedData(char *data) const
300 {
301   throw Exception("Not implemented yet : YACS::Any for objs ref");
302 }
303
304 const char * TypeCodeObjref::id() const throw(Exception)
305 {
306   return _repoId.c_str();
307 };
308
309 const char * TypeCodeObjref::name() const throw(Exception)
310 {
311   return _name.c_str();
312 }
313
314 const char * TypeCodeObjref::shortName() const
315 {
316   return _shortName.c_str();
317 }
318
319 TypeCodeObjref::TypeCodeObjref(const char* repositoryId,
320                                const char* name,
321                                const std::list<TypeCodeObjref *>& ltc) : TypeCodeComposed(Objref,repositoryId,name)
322 {
323   _listOfBases=ltc;
324   list<TypeCodeObjref *>::const_iterator iter;
325   for(iter=_listOfBases.begin();iter != _listOfBases.end(); iter++)
326     (*iter)->incrRef();
327 }
328
329 //! Check if this TypeCode is derived from a TypeCode with a given id
330 /*!
331  *   \param id :  a given id
332  *   \return     1 if true, 0 if false
333  */
334 int TypeCodeObjref::isA(const char* id) const throw(Exception)
335 {
336   if(_repoId == id)return 1;
337   list<TypeCodeObjref *>::const_iterator iter;
338   for(iter=_listOfBases.begin();iter != _listOfBases.end(); iter++)
339     {
340       if ((*iter)->isA(id)) return 1;
341     }
342   return 0;
343 }
344
345 //! Check if this TypeCode is derived from a given TypeCode
346 /*!
347  *   \param tc : the given TypeCode
348  *   \return    1 if true, 0 if false
349  */
350 int TypeCodeObjref::isA(const TypeCode* tc) const
351 {
352   return isA(tc->id());
353 }
354
355 //! Check if this TypeCode is adaptable to a given TypeCode (tc)
356 /*!
357  *   \param tc : the given TypeCode
358  *   \return    1 if true, 0 if false
359  */
360 int TypeCodeObjref::isAdaptable(const TypeCode* tc) const
361 {
362   if(_kind == tc->kind()) return isA(tc->id());
363   return 0;
364 }
365
366 //! Check if this TypeCode can be used in place of tc
367 /*!
368  * this TypeCode is equivalent to tc if they have the same kind
369  *
370  *   \param tc : the TypeCode to compare
371  */
372 int TypeCodeObjref::isEquivalent(const TypeCode* tc) const 
373 {
374   if(_kind != tc->kind())return 0;
375   if(_repoId == tc->id())return 1;
376   return 0;
377 }
378
379 TypeCodeObjref::TypeCodeObjref(const TypeCodeObjref& other):TypeCodeComposed(other),
380                                                             _listOfBases(other._listOfBases)
381 {
382   list<TypeCodeObjref *>::const_iterator iter;
383   for(iter=other._listOfBases.begin();iter!=other._listOfBases.end();iter++)
384     (*iter)->incrRef();
385 }
386
387 // --- TypeCodeSeq
388
389
390 //! Create a sequence type with a given name, a given id and a given contained type.
391 /*!
392  *   \param repositoryId : the given id
393  *   \param name : the given name
394  *   \param content : the given contained TypeCode
395  */
396 TypeCodeSeq::TypeCodeSeq(const char* repositoryId,
397                          const char* name, 
398                          const TypeCode *content) : TypeCodeComposed(Sequence,repositoryId,name), _content(content)
399 {
400   _content->incrRef();
401 }
402
403 TypeCodeSeq::~TypeCodeSeq()
404 {
405   ((TypeCode *)_content)->decrRef();
406 }
407
408 TypeCode *TypeCodeSeq::clone() const
409 {
410   return new TypeCodeSeq(*this);
411 }
412
413 void TypeCodeSeq::putReprAtPlace(char *pt, const char *val, bool deepCpy) const
414 {
415   SequenceAny::putReprAtPlace(pt,val,this,deepCpy);
416 }
417
418 void TypeCodeSeq::destroyZippedAny(char *data) const
419 {
420   SequenceAny::destroyReprAtPlace(data,this);
421 }
422
423 unsigned TypeCodeSeq::getSizeInByteOfAnyReprInSeq() const
424 {
425   return sizeof(void*);
426 }
427
428 AnyPtr TypeCodeSeq::getOrBuildAnyFromZippedData(char *data) const
429 {
430   return SequenceAny::getOrBuildFromData(data,this);
431 }
432
433 const char * TypeCodeSeq::id() const throw(Exception)
434 {
435   return _repoId.c_str();
436 }
437
438 const char * TypeCodeSeq::name() const throw(Exception)
439 {
440   return _name.c_str();
441 }
442 const char * TypeCodeSeq::shortName() const
443 {
444   return _shortName.c_str();
445 }
446
447 const TypeCode * TypeCodeSeq::contentType() const throw(Exception)
448 {
449   return _content;
450 }
451
452 int TypeCodeSeq::isA(const TypeCode* tc) const
453 {
454   if(_kind == tc->kind())
455     return _content->isA(tc->contentType());
456   return 0;
457 }
458
459 //! Check if this TypeCode is adaptable to a given TypeCode (tc)
460 /*!
461  *   \param tc : the given TypeCode
462  *   \return    1 if true, 0 if false
463  */
464 int TypeCodeSeq::isAdaptable(const TypeCode* tc) const
465 {
466   if(_kind == tc->kind())
467     return contentType()->isAdaptable(tc->contentType());
468   return 0;
469 }
470
471 //! Check if this TypeCode can be used in place of tc
472 /*!
473  * this TypeCode is equivalent to tc if they have the same kind
474  *
475  *   \param tc : the TypeCode to compare
476  */
477 int TypeCodeSeq::isEquivalent(const TypeCode* tc) const 
478 {
479   if(_kind == tc->kind())
480     return _content->isEquivalent(tc->contentType());
481   return 0;
482 }
483
484 TypeCodeSeq::TypeCodeSeq(const TypeCodeSeq& tc):TypeCodeComposed(tc),
485                                                 _content(tc._content)
486 {
487   _content->incrRef();
488 }
489
490 // --- TypeCodeArray
491
492
493 //! Create an Array type with a given name, a given id and a given contained type.
494 /*!
495  *   \param repositoryId : the given id
496  *   \param name : the given name
497  *   \param content : the given contained TypeCode
498  */
499 TypeCodeArray::TypeCodeArray(const char* repositoryId,
500                              const char* name, 
501                              const TypeCode *content,
502                              unsigned staticLgth) : TypeCodeComposed(Array,repositoryId,name), _content(content),_staticLgth(staticLgth)
503 {
504   _content->incrRef();
505 }
506
507 TypeCodeArray::~TypeCodeArray()
508 {
509   ((TypeCode *)_content)->decrRef();
510 }
511
512 TypeCode *TypeCodeArray::clone() const
513 {
514   return new TypeCodeArray(*this);
515 }
516
517 void TypeCodeArray::putReprAtPlace(char *pt, const char *val, bool deepCpy) const
518 {
519   ArrayAny::putReprAtPlace(pt,val,this,deepCpy);
520 }
521
522 void TypeCodeArray::destroyZippedAny(char *data) const
523 {
524   ArrayAny::destroyReprAtPlace(data,this);
525 }
526
527 AnyPtr TypeCodeArray::getOrBuildAnyFromZippedData(char *data) const
528 {
529   return ArrayAny::getOrBuildFromData(data,this);
530 }
531
532 const char * TypeCodeArray::id() const throw(Exception)
533 {
534   return _repoId.c_str();
535 }
536
537 const char * TypeCodeArray::name() const throw(Exception)
538 {
539   return _name.c_str();
540 }
541 const char * TypeCodeArray::shortName() const
542 {
543   return _shortName.c_str();
544 }
545
546 unsigned TypeCodeArray::getStaticLgth() const
547 {
548   return _staticLgth;
549 }
550
551 const TypeCode * TypeCodeArray::contentType() const throw(Exception)
552 {
553   return _content;
554 }
555
556 int TypeCodeArray::isA(const TypeCode* tc) const
557 {
558   if(_kind == tc->kind())
559     if(_content->isA(tc->contentType()))
560       {
561         const TypeCodeArray *tcC=dynamic_cast<const TypeCodeArray *>(tc);
562         if(tcC)
563           return tcC->getStaticLgth()==_staticLgth;
564         return 0;
565       }
566   return 0;
567 }
568
569 //! Check if this TypeCode is adaptable to a given TypeCode (tc)
570 /*!
571  *   \param tc : the given TypeCode
572  *   \return    1 if true, 0 if false
573  */
574 int TypeCodeArray::isAdaptable(const TypeCode* tc) const
575 {
576   if(_kind == tc->kind())
577     return contentType()->isAdaptable(tc->contentType());
578   return 0;
579 }
580
581 //! Check if this TypeCode can be used in place of tc
582 /*!
583  * this TypeCode is equivalent to tc if they have the same kind
584  *
585  *   \param tc : the TypeCode to compare
586  */
587 int TypeCodeArray::isEquivalent(const TypeCode* tc) const 
588 {
589   if(_kind == tc->kind())
590     return _content->isEquivalent(tc->contentType());
591   return 0;
592 }
593
594 TypeCodeArray::TypeCodeArray(const TypeCodeArray& tc):TypeCodeComposed(tc),
595                                                       _content(tc._content),
596                                                       _staticLgth(tc._staticLgth)
597 {
598   _content->incrRef();
599 }
600
601 unsigned TypeCodeArray::getSizeInByteOfAnyReprInSeq() const
602 {
603   return _staticLgth*_content->getSizeInByteOfAnyReprInSeq();
604 }
605
606 // --- TypeCodeStruct
607
608
609 //! Create a struct type with a given name and a given id 
610 /*!
611  *   \param repositoryId : the given id
612  *   \param name : the given name
613  */
614 TypeCodeStruct::TypeCodeStruct(const char* repositoryId, 
615                                const char* name) : TypeCodeComposed(Struct,repositoryId,name)
616 {
617 }
618
619 TypeCodeStruct::~TypeCodeStruct()
620 {
621 }
622
623 TypeCode *TypeCodeStruct::clone() const
624 {
625   return new TypeCodeStruct(*this);
626 }
627
628 TypeCodeStruct::TypeCodeStruct(const TypeCodeStruct& tc):TypeCodeComposed(tc),_members(tc._members)
629 {
630   for(vector< std::pair<std::string,TypeCode*> >::iterator iter=_members.begin();iter!=_members.end();iter++)
631     (*iter).second->incrRef();
632 }
633
634 void TypeCodeStruct::putReprAtPlace(char *pt, const char *val, bool deepCpy) const
635 {
636   StructAny::putReprAtPlace(pt,val,this,deepCpy);
637 }
638
639 void TypeCodeStruct::destroyZippedAny(char *data) const
640 {
641   StructAny::destroyReprAtPlace(data,this);
642 }
643
644 AnyPtr TypeCodeStruct::getOrBuildAnyFromZippedData(char *data) const
645 {
646   return StructAny::getOrBuildFromData(data,this);
647 }
648
649 const char * TypeCodeStruct::id() const throw(Exception)
650 {
651   return _repoId.c_str();
652 };
653
654 const char * TypeCodeStruct::name() const throw(Exception)
655 {
656   return _name.c_str();
657 }
658
659 const char * TypeCodeStruct::shortName() const
660 {
661   return _shortName.c_str();
662 }
663
664 unsigned TypeCodeStruct::getSizeInByteOfAnyReprInSeq() const
665 {
666   unsigned ret=0;
667   for(vector< pair<string,TypeCode*> >::const_iterator iter=_members.begin();iter!=_members.end();iter++)
668     ret+=(*iter).second->getSizeInByteOfAnyReprInSeq();
669   return ret;
670 }
671
672 const TypeCode *TypeCodeStruct::contentType() const throw(Exception)
673 {
674   const char what[]="Content type is specified by giving a key.";
675   throw Exception(what);
676 }
677
678 //! Check if this TypeCode is derived from a TypeCode with a given id
679 /*!
680  *   \param id :  a given id
681  *   \return     1 if true, 0 if false
682  */
683 int TypeCodeStruct::isA(const char* id) const throw(Exception)
684 {
685   if(_repoId == id)return 1;
686   return 0;
687 }
688
689 //! Check if this TypeCode is derived from a given TypeCode
690 /*!
691  *   \param tc : the given TypeCode
692  *   \return    1 if true, 0 if false
693  */
694 int TypeCodeStruct::isA(const TypeCode* tc) const 
695 {
696   if(_kind != tc->kind()) return 0;
697   if(_repoId == tc->id())return 1;
698   int nMember=memberCount();
699   if(nMember != ((TypeCodeStruct*)tc)->memberCount())return 0;
700   for(int i=0;i<nMember;i++)
701     {
702        const char * name=memberName(i);
703        if(strcmp(memberName(i),((TypeCodeStruct*)tc)->memberName(i)) != 0)return 0;
704        if(!memberType(i)->isA(((TypeCodeStruct*)tc)->memberType(i)))return 0;
705     }
706   return 1;
707 }
708
709 //! Check if this TypeCode is adaptable to a given TypeCode (tc)
710 /*!
711  *   \param tc : the given TypeCode
712  *   \return    1 if true, 0 if false
713  */
714 int TypeCodeStruct::isAdaptable(const TypeCode* tc) const
715 {
716   if(_kind == tc->kind()) return isA(tc->id());
717   return 0;
718 }
719
720 //! Check if this TypeCode can be used in place of tc
721 /*!
722  * this TypeCode is equivalent to tc if they have the same kind
723  *
724  *   \param tc : the TypeCode to compare
725  */
726 int TypeCodeStruct::isEquivalent(const TypeCode* tc) const 
727 {
728   if(_kind != tc->kind()) return 0;
729   int nMember=memberCount();
730   if(nMember != ((TypeCodeStruct*)tc)->memberCount())return 0;
731   for(int i=0;i<nMember;i++)
732     {
733        const char * name=memberName(i);
734        if(strcmp(memberName(i),((TypeCodeStruct*)tc)->memberName(i)) != 0)return 0;
735        if(!memberType(i)->isEquivalent(((TypeCodeStruct*)tc)->memberType(i)))return 0;
736     }
737   return 1;
738 }
739
740 void TypeCodeStruct::addMember(const std::string& name,TypeCode* tc)
741 {
742   DEBTRACE(name << " " << tc->name());
743   std::vector< std::pair<std::string,TypeCode*> >::const_iterator iter;
744   for(iter=_members.begin();iter != _members.end(); iter++)
745     {
746       if((*iter).first == name)
747         throw Exception("Struct member " + name + " already defined");
748     }
749   _members.push_back(std::pair<std::string,TypeCode*>(name,tc));
750 }
751
752 /*!
753  * If name is not an existing key, 0 is returned.
754  * \param offset : Out parameter, that specified the location of start of data discriminated by name key.
755  */
756 const TypeCode *TypeCodeStruct::getMember(const std::string& name, unsigned& offset) const
757 {
758   std::vector< std::pair<std::string,TypeCode*> >::const_iterator iter;
759   offset=0;
760   for(iter=_members.begin();iter != _members.end(); iter++)
761     {
762       if((*iter).first==name)
763         return (*iter).second;
764       offset+=(*iter).second->getSizeInByteOfAnyReprInSeq();
765     }
766   return 0;
767 }
768
769 int TypeCodeStruct::memberCount() const
770 {
771   return _members.size();
772 }
773
774 const char*  TypeCodeStruct::memberName(int index) const
775 {
776   if(index > _members.size())
777     {
778       stringstream msg;
779       msg << "Struct size less than " << index;
780       msg << " : " << __FILE__ << ":" << __LINE__;
781       throw Exception(msg.str());
782     }
783   return _members[index].first.c_str();
784 }
785
786 TypeCode*  TypeCodeStruct::memberType(int index) const
787 {
788   if(index > _members.size())
789     {
790       stringstream msg;
791       msg << "Struct size less than " << index;
792       msg << " : " << __FILE__ << ":" << __LINE__;
793       throw Exception(msg.str());
794     }
795   return _members[index].second;
796 }
797
798