TRUST 1.9.8
HPC thermohydraulic platform
Loading...
Searching...
No Matches
Type_info.cpp
1/****************************************************************************
2* Copyright (c) 2022, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15
16#include <Type_info.h>
17#include <Noms.h>
18#include <Synonyme_info.h>
19
20// B.Mathieu, 08/2004
21// Le processus d'initialisation de ces membres statiques est tres
22// important : il faut absolument qu'ils soient initialises AVANT
23// le premier appel au constructeur Type_info::Type_info(...).
24// Or ce constructeur est appele pour initialiser le membre statique info_obj
25// de tous les Objet_U.
26// Risque de "static initialization order fiasco"
27// (voir http://www.parashift.com/c++-faq-lite/ctors.html [10.11])
28// Pour l'instant c'est ok parce qu'on initialise avec une constante...
29
30// Tableau de pointeurs sur les types enregistres lors de la construction
31// des Type_info. Si plusieurs types on le meme nom (Type_info::n), alors
32// on n'en enregistre qu'un seul dans Type_info::les_types.
33const Type_info** Type_info::les_types=0;
34// Pour chaque elements du tableau "les_types", ce nombre vaut 1 si le
35// nom du type est commun a plusieurs types, 0 sinon.
36// Voir "ajouter_type"
37int * Type_info::types_homonymes=0;
38
39int Type_info::nb_classes=0;
40int Type_info::les_types_memsize=0;
41
42
43// [ABN] I don't dare replacing this with STL for efficiency purpose - here we convert only what's needed for comparison
44static inline int strcmp_uppercase(const char *n1, const char *n2)
45{
46 int i = 0;
47 unsigned char c1, c2;
48 int delta;
49 do
50 {
51 c1 = (unsigned char) ::toupper(n1[i]);
52 c2 = (unsigned char) ::toupper(n2[i]);
53 delta = c1 - c2;
54 i++;
55 }
56 while ((delta == 0) && (c1 != 0) && (c2 != 0));
57 return delta;
58}
59
60// GF pour liberer correctement la memoire il faut au moins detruire
61// le Nom
63{
64 // On cherche ou retirer le type dans le tableau :
65 int index;
66 int existe_deja = search_type_info_name(name(), index);
67 if (existe_deja)
68 {
69 for (int i = index; i<nb_classes-1; i++)
70 {
71 les_types[i] = les_types[i+1];
72 types_homonymes[i] = types_homonymes[i+1];
73 }
74 nb_classes--;
75 }
76 if (name_)
77 {
78 delete name_;
79 name_=0;
80 delete synonym_;
81 synonym_=0;
82 delete synonym_name_;
83 synonym_name_=0;
84 }
85 if ((nb_classes==0)&& (les_types_memsize!=0))
86 {
87 delete [] les_types;
88 delete [] types_homonymes;
89 les_types_memsize=0;
90 }
91}
92
93/*! @brief Recherche le type de nom "nom" dans la liste de types enregistres par une recherche binaire.
94 *
95 * On compare les chaines converties en majuscules.
96 * On range dans "index" l'indice du type, s'il a ete trouve
97 * et sinon l'indice du type juste apres (dans ce cas, on a
98 * les_types[index-1]->n < nom < les_types[index]->n )
99 * Si le type a ete trouve on renvoie 1, sinon 0.
100 *
101 */
102int Type_info::search_type_info_name(const char *nom, int& index)
103{
104 assert(nom != 0);
105 // [imin..imax] est l'intervalle ou se trouve l'index recherche
106 int imin = 0;
107 int imax = nb_classes;
108 while (imax > imin)
109 {
110 // On a toujours milieu < imax
111 int milieu = (imin + imax) / 2;
112 int comparaison = strcmp_uppercase(nom, les_types[milieu]->name());
113 if (comparaison == 0)
114 {
115 index = milieu;
116 return 1;
117 }
118 if (comparaison < 0)
119 {
120 // nom < les_types[milieu]
121 // l'index recherche est donc inferieur ou egal a "milieu"
122 imax = milieu;
123 }
124 else
125 {
126 // nom > les_types[milieu]
127 // l'index recherche est donc strictement superieur a "milieu"
128 imin = milieu + 1;
129 }
130 }
131 index = imax;
132 return 0;
133}
134/*! @brief Constructeur par un nom, un tableau de meres.
135 *
136 * @param (const char* nom) le nom du type a creer
137 * @param (int nb_base) le nombre de meres dans le tableau bases
138 * @param (const Type_info* bases[]) le tableau specifiant les types de bases (meres) du type a creer
139 * @throws Sort en erreur si le nom n'est pas defini (null)
140 */
141Type_info::Type_info(const char* un_nom, int nb_base, const Type_info** the_bases) :
142 names_(un_nom),
143 name_((Nom*)0),
144 synonym_name_((Nom*) 0),
145 nb_bases_(nb_base),
146 b(the_bases),
147 cree_instance(0)
148{
149 if(un_nom == 0)
150 {
151 Cerr << "Type_info::Type_info(const char* nom,Objet_U* (*f)()...)\n";
152 Cerr << " Error : name == 0" << finl;
153 assert(0);
155 }
156 ajouter_type(*this);
157}
158
159/*! @brief Constructeur par un nom, une fonction et un tableau de meres.
160 *
161 * La fonction permet de creer une instance du bon type.
162 *
163 * @param (const char* nom) le nom du type a creer
164 * @param (Objet_U* (*f)()) fonction pour creer une instance du type considere
165 * @param (int nb_base) le nombre de meres dans le tableau bases[]
166 * @param (const Type_info* bases[]) le tableau specifiant les types de bases (meres) du type a creer
167 * @throws Sort en erreur si le nom donne n'est pas defini (null)
168 */
169Type_info::Type_info(const char* un_nom,
170 Objet_U* (*f)(),
171 int nb_base,
172 const Type_info** the_bases) :
173 names_(un_nom),
174 name_((Nom*) 0),
175 synonym_name_((Nom*) 0),
176 nb_bases_(nb_base),
177 b(the_bases),
178 cree_instance(f)
179{
180 if(un_nom == 0)
181 {
182 Cerr << "Type_info::Type_info(const char* nom,Objet_U* (*f)()...)\n";
183 Cerr << " Error : name == 0" << finl;
184 assert(0);
186 }
187 ajouter_type(*this);
188}
189
190/*! @brief Methode statique appelee par les constructeurs de Type_info pour ajouter un nouveau type a la liste des types enregistres.
191 *
192 * Verifie que le nom du type n'existe pas encore.
193 *
194 */
195void Type_info::ajouter_type(const Type_info& type_info)
196{
197 // Split type_info.names_ into A if | is found (eg: n=A|B)
198 // and add a synonym B
199 Nom A("");
200 Nom B("");
201 int synonym_found=0;
202 int i = 0;
203 unsigned char c;
204 do // Start loop
205 {
206 c = type_info.names_[i];
207 // Find a |
208 if (c==124)
209 {
210 if (synonym_found==1)
211 {
212 Cerr << "More than 1 synonym found in " << type_info.names_ << finl;
213 Cerr << "Not supported yet !" << finl;
215 }
216 else
217 {
218 synonym_found=1;
219 i++;
220 c = type_info.names_[i];
221 if (c==0)
222 {
223 Cerr << "Error in a classname which can't finished by | : " << type_info.names_ << finl;
225 }
226 }
227 }
228 // Build the synonym name:
229 if (synonym_found)
230 B+=c;
231 else
232 A+=c;
233 i++;
234 }
235 while (c!=0); // End loop
236
237 name_ = new Nom(A);
238 if (synonym_found)
239 {
240 //Commented cause too verbose:
241 //Cerr << "Keyword " << A << " has a synonym: " << B << finl;
242 synonym_name_ = new Nom(B);
243 synonym_ = new Synonyme_info(synonym_name_->getChar(),name_->getChar());
244 }
245 // Verifie qu'il y a assez de place dans le tableau :
246 if (les_types_memsize <= nb_classes + 1)
247 {
248 static const int INCREMENT = 512;
249 // Plus assez de place dans le tableau: on redimensionne.
250 les_types_memsize += INCREMENT;
251 const Type_info** nouveau = new const Type_info*[les_types_memsize];
252 for (int j = 0; j < nb_classes; j++)
253 nouveau[j] = les_types[j];
254 delete[] les_types;
255 les_types = nouveau;
256
257 int * temp = new int[les_types_memsize];
258 for (int j = 0; j < nb_classes; j++)
259 temp[j] = types_homonymes[j];
260 delete[] types_homonymes;
261 types_homonymes = temp;
262 }
263
264 // On cherche ou mettre le type dans le tableau :
265 int existe_deja=Synonyme_info::est_un_synonyme(type_info.name());
266 if (existe_deja)
267 {
268 Cerr<<" class "<<type_info.name()<<" already exists as a synonym which is forbidden!!!!"<<finl;
270 }
271 int index;
272 existe_deja = search_type_info_name(type_info.name(), index);
273 if (existe_deja)
274 {
275 types_homonymes[index] = 1;
276 // GF: si on a un homonyme que la macro string_macro_trio fonctionne
277 // on a un pb sauf pour les iterateurs
278 if (strcmp(string_macro_trio("VECT",titi),"VECT"))
279 {
280 if (strncmp(type_info.name(),"Iterateur_",10))
281 {
282 Cerr<<" type "<<type_info.name()<<" is in double and it is not allowed!!!!"<<finl;
284 }
285 }
286 }
287 else
288 {
289 // Ajout du type dans le tableau a l'indice "index":
290 for (int j = nb_classes; j > index; j--)
291 {
292 les_types[j] = les_types[j-1];
293 types_homonymes[j] = types_homonymes[j-1];
294 }
295 les_types[index] = &type_info;
296 types_homonymes[index] = 0;
297 nb_classes++;
298 }
299}
300
301/*! @brief Ecriture des bases du type considere sur un flot de sortie
302 *
303 * @param (Sortie& os) flot de sortie
304 * @return (Sortie&) le flot de sortie modifie
305 */
307{
308 int i= nb_bases_;
309 while(i--)
310 os << b[i]->name() << " ";
311 return os << finl;
312}
313
314/*! @brief Ecriture de toute la hierarchie du type considere sur un flix de sortie
315 *
316 * @param (Sortie& os) flot de sortie
317 * @return (Sortie&) le flot de sortie modifie
318 */
320{
321 os << "There is " << nb_classes << " classes:" << finl;
322 int i= nb_classes;
323 while(i--)
324 {
325 os << les_types[i]->name() << " inherits from ";
326 les_types[i]->bases(os);
327 }
328 return os << flush;
329}
330
331/*! @brief Instanciation d'un Objet_U du type indique S'il existe une classe T dont le Type_info a
332 *
333 * le nom typ, alors instance renvoie un pointeur
334 * sur une nouvelle instance de T.
335 * renvoie le pointeur nul sinon.
336 *
337 * @param (const char* typ) chaine de caractere associee a un type
338 * @return (Objet_U*) pointeur sur un nouvel Objet_U du type typ
339 */
341{
342 const Type_info * le_type = type_info_from_name(typ);
344 if (le_type)
345 instance = le_type->instance();
346 else
347 instance = 0;
348 return instance;
349}
350
351/*! @brief Cree une instance de la classe associee au type_info.
352 *
353 */
355{
356 if (cree_instance == 0)
357 {
358 Cerr << "Error in Type_info::instance()\n";
359 Cerr << " The type " << name() << " is not instantiable" << finl;
360 assert(0);
362 }
363 Objet_U * ainstance = (*cree_instance)();
364 return ainstance;
365}
366
367/*! @brief Test d'existence d'une classe du type indique si il existe une classe T dont le Type_info a
368 *
369 * le nom nom, alors est_un_type renvoie 1
370 * renvoie le pointeur nul sinon.
371 *
372 * @param (const char* nom) chaine de caractere associee a un type
373 * @return (int) code de retour (0 ou 1)
374 */
375int Type_info::est_un_type(const char* nom)
376{
377 const Type_info * type = type_info_from_name(nom);
378 return (type != 0);
379}
380
381/*! @brief Test d'appartenance d'un type dans les types de bases du type considere si direct == 0
382 *
383 * renvoie 1 si (*p) fait partie des bases de (*this)
384 * renvoie 0 sinon.
385 * si direct != 0
386 * renvoie 1 si (*p) fait partie des bases de (*this)
387 * ou des meres directes ou non de (*this)
388 * renvoie 0 sinon.
389 *
390 * @param (const Type_info* p) le pointeur sur le type a rechercher
391 * @param (int direct) 0 pour une recherche dans toute la hierarchie des bases, non nul pour une recherche directe
392 * @return (int) code de retour (0 ou 1)
393 */
394int Type_info::has_base(const Type_info* p, int direct) const
395{
396 //recherche de p->name() dans b
397 // si trouve return 1
398 // sinon si pas direct return 0;
399 // sinon recherche dans les bases de b
400 // Modif de B. Mathieu: test uniquement sur l'adresse du type_info,
401 // pas sur le nom du type...
402 if (p == 0)
403 {
404 return 0;
405 }
406 else
407 {
408 if (p == this)
409 {
410 return 1;
411 }
412 else
413 {
414 for (int i = 0; i < nb_bases_; i++)
415 if (b[i] == p)
416 return 1;
417 if (!direct)
418 {
419 // Verifier les ancetres de niveau superieur
420 for (int i = 0; i < nb_bases_; i++)
421 if (b[i]->has_base(p, direct)) return 1;
422 }
423 }
424 }
425 return 0;
426}
427
428/*! @brief Test d'appartenance d'un type dans les types de bases du type considere Le type a rechercher est identifie par son nom
429 *
430 * si direct == 0
431 * renvoie 1 si le type de nom name fait partie des bases de (*this)
432 * renvoie 0 sinon.
433 * si direct != 0
434 * renvoie 1 si le type de nom name fait partie des bases de (*this)
435 * ou des meres directes ou non de (*this)
436 * renvoie 0 sinon.
437 *
438 * @param (const Nom& name) le nom du type a rechercher
439 * @param (int direct) 0 pour une recherche dans toute la hierarchie des bases, non nul pour une recherche directe
440 * @return (int) code de retour (0 ou 1)
441 */
442int Type_info::has_base(const Nom& aname, int direct) const
443{
444 //recherche de aname dans b
445 // si trouve return 1
446 // sinon si pas direct return 0;
447 // sinon recherche dans les bases de b
448 // Modif B. Mathieu: comparaison des adresses du Type_info uniquement,
449 // pas du nom du type.
450
451 const Type_info * type = type_info_from_name(aname);
452 int resultat = has_base(type, direct);
453 return resultat;
454}
455
456/*! @brief Comparaison sur le nom d'un type Retourne 1 si les chaines de caracteres des noms du type considere et du nom indique sont identiques
457 *
458 * Retour 0 sinon
459 *
460 */
461int Type_info::same(const Nom& other_name) const
462{
463 return strcmp(name(),other_name)==0;
464}
465
466/*! @brief Renvoie 1 si this==p, 0 sinon.
467 *
468 */
469int Type_info::same(const Type_info* p) const
470{
471 return (this == p);
472}
473
474/*! @brief Donne les noms des sous-types, un type mere etant donne
475 *
476 * @param (const Type_info& mere) le type sur lequel rechercher les sous-types
477 * @param (Noms& les_sous_types) les noms des sous-types
478 * @return (int) nombre de sous-types retournes
479 */
481{
482 int compteur=0;
483 int i= nb_classes;
484 // Modif B. Mathieu: name() ne renvoie plus un static.
485 const Nom& nom_mere = mere.name();
486 // Cerr << "---------" << (const char*) nom_mere << finl;
487 while(i--)
488 {
489 if( les_types[i]->has_base(nom_mere, 0) )
490 if (!les_types[i]->same(nom_mere))
491 {
492 compteur++;
493 }
494 }
495 // Cerr << compteur << finl ;
496 if(compteur==0) return 0;
497 les_sous_types.dimensionner(compteur);
498 compteur=0;
499 i= nb_classes;
500 while(i--)
501 {
502 if( les_types[i]->has_base(nom_mere, 0) )
503 if (!les_types[i]->same(nom_mere))
504 {
505 les_sous_types[compteur++]=les_types[i]->name();
506 }
507 }
508 return compteur;
509}
510
511/*! @brief Donne les noms des sous-types, un type mere etant donne par son nom
512 *
513 * @param (const Nom& type) le nom du type sur lequel rechercher les sous-types
514 * @param (Noms& les_sous_types) les noms des sous-types
515 * @return (int) nombre de sous-types retournes
516 * @throws Sort en erreur si le nom indique ne correspond pas a un type existant dans TRUST
517 */
518int Type_info::les_sous_types(const Nom& type, Noms& sous_types)
519{
520 if (!est_un_type(type))
521 {
522 Cerr << type << "is not a type recognized by TRUST Unitaire " << finl;
524 }
525 int i= nb_classes;
526 while(i--)
527 {
528 const Type_info& mere = *les_types[i];
529 if( les_types[i]->same(type) )
530 {
531 return les_sous_types(mere, sous_types);
532 }
533 }
534 return 0;
535}
536
537/*! @brief Methode statique qui renvoie un pointeur vers le Type_info dont le nom est "type_name".
538 *
539 * Si type_name n'est pas un type,
540 * renvoie un pointeur nul.
541 *
542 */
543
544const Type_info * Type_info::type_info_from_name(const char * type_name)
545{
546 const Type_info * type_info = nullptr;
547 if (type_name != 0)
548 {
549 int index;
550 if (search_type_info_name(type_name, index))
551 {
552 if (types_homonymes[index] == 0)
553 {
554 type_info = les_types[index];
555 }
556 else
557 {
558 // Le type est enregistre mais le nom correspond
559 // a plusieurs types...
560 Cerr << "const Type_info * Type_info::type_info_from_name(const char * type_name)\n";
561 Cerr << " The type " << type_name << " has several homonymous\n";
562 Cerr << " We doing as if the type is unknown..." << finl;
563 }
564 }
565 }
566 return type_info;
567}
568
569/*! @brief Renvoie 1 si le type associe est instanciable (cree_instance non nul) renvoie 0 sinon.
570 *
571 */
573{
574 return (cree_instance != 0);
575}
576
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
Un tableau de chaine de caracteres (VECT(Nom)).
Definition Noms.h:26
classe Objet_U Cette classe est la classe de base des Objets de TRUST
Definition Objet_U.h:73
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
Classe de base des flux de sortie.
Definition Sortie.h:52
static int est_un_synonyme(const char *)
Test d'existence d'une classe du synonyme indique si il existe une classe T dont le Synonyme_info a.
modelise une information de type pour les Objet_U
Definition Type_info.h:30
int instanciable() const
Renvoie 1 si le type associe est instanciable (cree_instance non nul) renvoie 0 sinon.
static int les_sous_types(const Nom &, Noms &sous_types)
Donne les noms des sous-types, un type mere etant donne par son nom.
Type_info(const char *name, Objet_U *(*f)(), int nb_bases=0, const Type_info **bases=0)
Constructeur par un nom, une fonction et un tableau de meres.
Objet_U * instance() const
Cree une instance de la classe associee au type_info.
int has_base(const Type_info *p, int direct=0) const
Test d'appartenance d'un type dans les types de bases du type considere si direct == 0.
int same(const Type_info *p) const
Renvoie 1 si this==p, 0 sinon.
static int est_un_type(const char *)
Test d'existence d'une classe du type indique si il existe une classe T dont le Type_info a.
static Sortie & hierarchie(Sortie &)
Ecriture de toute la hierarchie du type considere sur un flix de sortie.
static const Type_info * type_info_from_name(const char *type_name)
Methode statique qui renvoie un pointeur vers le Type_info dont le nom est "type_name".
Sortie & bases(Sortie &) const
Ecriture des bases du type considere sur un flot de sortie.
const Nom & name() const
Definition Type_info.h:36