TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
communications.cpp
1/****************************************************************************
2* Copyright (c) 2026, 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 <InOutCommBuffers.h>
17#include <communications.h>
18#include <Schema_Comm.h>
19#include <TRUSTArrays.h>
20#include <TRUSTTabs.h>
21#include <TRUSTTab.h>
22#include <Motcle.h>
23
24/*! @brief Envoi de messages point-to-point synchrone entre la source et la cible.
25 *
26 * La fonction envoyer se termine au plus tard lorsque le message a ete
27 * recu par l'instruction "recevoir" correspondante et l'envoi peut etre blocant
28 * (le blocage est force en mode debug, selon Comm_Group::check_enabled() )
29 * Ces communications utilisent Comm_Group::send() et Comm_Group::recv()
30 * Exemples d'utilisations possibles:
31 * 1) communication point-a-point (processeur 2 vers processeur 5)
32 * if (me() == 2)
33 * envoyer(objet, 5, canal);
34 * else if (me() == 5)
35 * recevoir(objet, 2, canal);
36 * ou de facon equivalente :
37 * envoyer(objet, 2, 5, canal); // ne fait rien sur les processeurs autres que 2
38 * recevoir(objet, 2, 5, canal); // ne fait rien sur les processeurs autres que 5
39 * 2) gather : le processeur 0 recupere les donnees de l'objet t de tout le monde
40 * envoyer(t, me(), 0, canal); // Tout le monde envoie au processeur 0, sur le maitre, ne fait rien
41 * if (je_suis_maitre())
42 * for (i = 0; i < nproc(); i++) {
43 * recevoir(t, 0, i; canal); // Si i==0, ne fait rien.
44 * ... faire quelque chose avec t
45 * }
46 * 3) broadcast : le processeur 0 envoie l'objet a tous les autres processeurs
47 * Il n'est pas necessaire de faire le test "if (je_suis_maitre())"
48 * envoyer(objet, 0, -1, canal); // Les processeurs autres que 0 ignorent l'appel
49 * recevoir(objet, 0, -1, canal);// Le processeur 0 ignore l'appel
50 * Il vaut mieux utiliser envoyer_broadcast() pour cet usage.
51 * 4) broadcast : ecriture equivalente
52 * if (je_suis_maitre())
53 * envoyer(objet, -1, canal); // Emission par le maitre a tous les processeurs, sauf lui-meme
54 * else
55 * recevoir(objet, 0, canal); // Reception d'un message du processeur maitre
56 * Il vaut mieux utiliser envoyer_broadcast() pour cet usage.
57 * Dans l'implementation de envoyer_, on encapsule l'objet recu dans un buffer et on envoie le buffer.
58 * Ca marche donc pour les types complexes pourvu que Entree et Sortie sachent lire et ecrire l'objet.
59 * Chaque envoi necessite l'envoi de deux messages : d'abord la taille du buffer, puis le contenu.
60 *
61 */
62template <typename T>
63bool envoyer_buffered_(const T& objet, int source, int cible, int canal)
64{
65 const int moi = Process::me();
66 if (moi == cible)
67 return false;
68
69 if (source != moi && source != -1)
70 return false;
71
72 OutputCommBuffer buffer;
73 buffer << objet;
74 const char * data = buffer.get_buffer();
75 const int sz = buffer.get_buffer_size();
77 if (cible < 0)
78 {
79 const int n = grp.nproc();
80 for (int i = 0; i < n; i++)
81 {
82 if (i != moi)
83 {
84 grp.send(i, &sz, sizeof(int), canal);
85 grp.send(i, data, sz, canal);
86 }
87 }
88 }
89 else
90 {
91 grp.send(cible, &sz, sizeof(int), canal);
92 grp.send(cible, data, sz, canal);
93 }
94 return true;
95}
96
97/*! @brief Reception d'un message en provenance du processeur source
98 *
99 */
100template <typename T>
101bool recevoir_buffered_(T& objet, int source, int cible, int canal)
102{
103 const int moi = Process::me();
104 if (moi == source)
105 return false;
106
107 if (cible != moi && cible != -1)
108 return false;
109
110 int sz;
112 grp.recv(source, &sz, sizeof(int), canal);
113 InputCommBuffer buffer;
114 char * data = buffer.reserve_buffer(sz);
115 grp.recv(source, data, sz, canal);
116 buffer.create_stream();
117 buffer >> objet;
118 buffer.clear();
119 return true;
120}
121
122/*! @brief Broadcast de l'objet par le processeur source a tous les autres processeurs.
123 *
124 * Fonctionne pour des types complexes supportes par Entree ou Sortie.
125 *
126 */
127template <typename T>
128bool envoyer_broadcast_buffered_(T& objet, int source)
129{
131 if (grp.rank() == source)
132 {
133 OutputCommBuffer buffer;
134 buffer << objet;
135 const char * data = buffer.get_buffer();
136 int sz = buffer.get_buffer_size();
137 grp.broadcast(&sz, sizeof(int), source);
138 grp.broadcast((char*) data, sz, source);
139 }
140 else
141 {
142 int sz;
143 grp.broadcast(&sz, sizeof(int), source);
144 InputCommBuffer buffer;
145 char * data = buffer.reserve_buffer(sz);
146 grp.broadcast((char*) data, sz, source);
147 buffer.create_stream();
148 buffer >> objet;
149 buffer.clear();
150 }
151 return true;
152}
153
154bool envoyer(const Objet_U& t, int source, int cible, int canal)
155{
156 return envoyer_buffered_(t, source, cible, canal);
157}
158
159bool envoyer(const Objet_U& t, int cible, int canal)
160{
161 return envoyer_buffered_(t, Process::me(), cible, canal);
162}
163
164bool recevoir(Objet_U& t, int source, int cible, int canal)
165{
166 return recevoir_buffered_(t, source, cible, canal);
167}
168
169bool recevoir(Objet_U& t, int source, int canal)
170{
171 return recevoir_buffered_(t, source, Process::me(), canal);
172}
173
174bool envoyer_broadcast(Objet_U& t, int source)
175{
176 return envoyer_broadcast_buffered_(t, source);
177}
178
179// Template qui marche pour tout objet T qui ressemble a un vecteur (possede un operator[]) de taille nproc()
180template <typename T>
181bool envoyer_all_to_all_(const T& src, T& dest)
182{
184 assert(src.size() == Process::nproc());
185 assert(dest.size() == Process::nproc());
186 Schema_Comm sch;
187 const int nproc = grp.nproc();
188 const int moi = grp.rank();
189 dest[moi] = src[moi];
190 ArrOfInt send_pe_list(1);
191 ArrOfInt recv_pe_list(1);
192 for (int p = 1; p < nproc; p++)
193 {
194 const int send_to = (moi + p) % nproc;
195 const int recv_from = (moi + nproc - p) % nproc;
196 send_pe_list[0] = send_to;
197 recv_pe_list[0] = recv_from;
198 sch.set_send_recv_pe_list(send_pe_list, recv_pe_list);
199 sch.begin_comm();
200 sch.send_buffer(send_to) << src[send_to];
202 sch.recv_buffer(recv_from) >> dest[recv_from];
203 sch.end_comm();
204 }
205 return true;
206}
207
208bool envoyer_all_to_all(const TRUST_Vector<TRUSTTab<double>>& src, TRUST_Vector<TRUSTTab<double>>& dest)
209{
210 return envoyer_all_to_all_(src, dest);
211}
212
213bool envoyer_all_to_all(const TRUST_Vector<TRUSTArray<int>>& src, TRUST_Vector<TRUSTArray<int>>& dest)
214{
215 return envoyer_all_to_all_(src, dest);
216}
217
218#if INT_is_64_ == 2
219bool envoyer_all_to_all(const TRUST_Vector<TRUSTArray<trustIdType>>& src, TRUST_Vector<TRUSTArray<trustIdType>>& dest)
220{
221 return envoyer_all_to_all_(src, dest);
222}
223#endif
224
225/*! @brief On suppose que les tableaux en entree et en sortie sont de taille nproc() .
226 *
227 * On envoie src[0] au proc 0,
228 * src[1] au proc 1, etc... la valeur recue du processeur 0 et mise dans
229 * dest[0], processeur 1 dans dest[1], etc...
230 * Il est autorise d'appeler la fonction avec le meme tableau src et dest.
231 *
232 */
233bool envoyer_all_to_all(std::vector<long long>& src, std::vector<long long>& dest)
234{
236 assert(static_cast<int>(src.size()) == grp.nproc());
237 assert(static_cast<int>(dest.size()) == grp.nproc());
238 if (src.data() == dest.data())
239 {
240 std::vector<long long> tmp(grp.nproc(),0);
241 grp.all_to_all(src.data(), tmp.data(), sizeof(long long));
242 dest = tmp;
243 }
244 else
245 {
246 grp.all_to_all(src.data(), dest.data(), sizeof(long long));
247 }
248 return true;
249}
250
251/*! @brief Calcule la transposee d'une liste de processeurs: On construit le tableau dest_list tel que:
252 *
253 * x est dans la liste src_list sur le processeur y
254 * si et seulement si
255 * y est dans la liste dest_list sur le processeur x
256 * En pratique, cette fonction permet de calculer la liste des
257 * processeurs qui recoivent des messages si on connait la liste
258 * des processeurs qui envoient des messages, et reciproquement.
259 *
260 * @param (src_list) Une liste de numeros de PEs presents dans ce groupe de comm. Ce sont les indices des pes dans le groupe courant (0 <= pe < nproc_)
261 * @param (dest_list) Le tableau ou stocker le resultat. On le met a la bonne taille et on le remplit. Les numeros de PEs sont mis dans l'ordre croissant. Ce sont les indices des pes dans le groupe courant (0 <= pe < nproc_)
262 */
263bool reverse_send_recv_pe_list(const ArrOfInt& src_list, ArrOfInt& dest_list)
264{
266 const int np = grp.nproc();
267 assert(src_list.size_array() == 0 || max_array(src_list) < np);
268 assert(src_list.size_array() == 0 || min_array(src_list) >= 0);
269 ArrOfInt flag(np);
270 int i;
271 const int src_size = src_list.size_array();
272 for (i = 0; i < src_size; i++)
273 {
274 const int pe = src_list[i];
275 flag[pe] = 1;
276 }
277 ArrOfInt flag_recv(np);
278 envoyer_all_to_all(flag, flag_recv);
279 int n = 0;
280 dest_list.resize_array(np);
281 for (i = 0; i < np; i++)
282 if (flag_recv[i])
283 dest_list[n++] = i;
284 dest_list.resize_array(n);
285 return true;
286}
287
288/*! @brief On suppose que les tableaux en entree et en sortie sont tels que dimension(0)==nproc() et que les autres dimensions
289 *
290 * sont identiques. On envoie src(0, i, j, ...) au proc 0,
291 * src(0, i, j, ...) au proc 1, etc... la valeur recue du processeur 0 et mise dans
292 * dest(0, i, j, ...) , processeur 1 dans dest(1, i, j, ...) , etc...
293 * Il est autorise d'appeler la fonction avec le meme tableau src et dest.
294 *
295 */
296void envoyer_all_to_all(const DoubleTab& src, DoubleTab& dest)
297{
299 assert(src.dimension(0) == grp.nproc());
300 assert(dest.dimension(0) == grp.nproc());
301 assert(src.size_array() == dest.size_array());
302
303 if (dest.data() == src.data())
304 {
305 DoubleTab tmp(src);
306 envoyer_all_to_all(src, tmp);
307 dest = tmp;
308 }
309 else
310 {
311 const int sz = src.size() / grp.nproc() * (int)sizeof(double);
312 grp.all_to_all(src.data(), dest.data(), sz);
313 }
314}
315template <typename T>
316void envoyer_all_gather_(const TRUSTTab<T>& src, TRUSTTab<T>& dest)
317{
319
320 if (dest.addr() == src.addr())
321 {
322 assert(src.dimension(0) == grp.nproc());
323 assert(dest.dimension(0) == grp.nproc());
324 const int sz = src.size() / grp.nproc() * (int)sizeof(T);
325 TRUSTTab<T> tmp(src);
326 grp.all_gather(src.addr(), tmp.addr(), sz);
327 dest = tmp;
328 }
329 else
330 {
331 const int sz = src.size() * (int)sizeof(T);
332 assert( dest.size_array() == grp.nproc()*src.size_array());
333 grp.all_gather(src.addr(), dest.addr(), sz);
334 }
335}
336
337template <typename T>
338void envoyer_gather_(const TRUSTTab<T>& src, TRUSTTab<T>& dest, int root)
339{
341
342 if (dest.addr() == src.addr())
343 {
344 assert(src.dimension(0) == grp.nproc());
345 assert(dest.dimension(0) == grp.nproc());
346 const int sz = src.size() / grp.nproc() * (int)sizeof(T);
347 TRUSTTab<T> tmp(src);
348 grp.gather(src.addr(), tmp.addr(), sz, root);
349 dest = tmp;
350 }
351 else
352 {
353 const int sz = src.size() * (int)sizeof(T);
354 assert( dest.size_array() == grp.nproc()*src.size_array());
355 grp.gather(src.addr(), dest.addr(), sz, root);
356 }
357}
358
359void envoyer_gather(const DoubleTab& src, DoubleTab& dest, int root)
360{
361 envoyer_gather_(src,dest,root);
362}
363
364void envoyer_gather(const IntTab& src, IntTab& dest, int root)
365{
366 envoyer_gather_(src,dest,root);
367}
368
369void envoyer_all_gather(const DoubleTab& src, DoubleTab& dest)
370{
371 envoyer_all_gather_(src,dest);
372}
373
374void envoyer_all_gather(const IntTab& src, IntTab& dest)
375{
376 envoyer_all_gather_(src,dest);
377}
378
379void envoyer_all_gatherv(const DoubleTab& src, DoubleTab& dest, const IntTab& recv_size)
380{
382
383 assert(dest.size_array()==local_somme_vect(recv_size));
384 assert(src.size_array()==recv_size[grp.me()]);
385
386 const int nbprocs = (int)grp.nproc();
387
388 std::vector<int> sz(nbprocs);
389 for (int p=0; p<nbprocs; p++)
390 sz[p] = recv_size[p] * (int)sizeof(double);
391
392 int sz0 = src.size() * (int)sizeof(double);
393
394 std::vector<int> displs(nbprocs);
395 displs[0] = 0;
396 for (int p=1; p<nbprocs; p++)
397 displs[p] = displs[p-1]+sz[p-1];
398
399 grp.all_gatherv(src.addr(), dest.addr(), sz0 , sz.data(),displs.data());
400}
401
402
403/*! @brief renvoie le drapeau Comm_Group::check_enabled().
404 *
405 * Ce drapeau indique si le code tourne en mode DEBUG du parallele. Dans ce cas, des communications supplementaires ont lieu pour verifier la coherence du parallelisme et le mode de communication
406 * est force en mode synchrone. Cette methode permet de tester le drapeau, et s'il est mis de realiser des verifications supplementaires
407 *
408 */
409bool comm_check_enabled() { return Comm_Group::check_enabled(); }
410
411/*! @brief renvoie 1 (sur tous les procs) si le parametre est identique sur tous les procs, sinon renvoie 0 (sur tous les procs)
412 *
413 */
414bool is_parallel_object(const int x)
415{
416 const int x1 = Process::mp_min(x);
417 const int x2 = Process::mp_max(x);
418 return x1 == x2;
419}
420
421#if INT_is_64_ == 2
422bool is_parallel_object(const trustIdType x)
423{
424 const trustIdType x1 = Process::mp_min(x);
425 const trustIdType x2 = Process::mp_max(x);
426 return x1 == x2;
427}
428#endif
429
430/*! @brief renvoie 1 (sur tous les procs) si le parametre est identique sur tous les procs, sinon renvoie 0 (sur tous les procs)
431 *
432 */
433bool is_parallel_object(const double x)
434{
436 double tab_x[2];
437 tab_x[0] = x;
438 tab_x[1] = x;
439 double tab_y[2];
441 grp.mp_collective_op(tab_x, tab_y, tab_op, 2);
442 return tab_y[0] == tab_y[1];
443}
444
445template <class T> int compare(const Objet_U& a, const Objet_U& b, int& erreur)
446{
447 if (sub_type(T, a))
448 {
449 const T& a_ = static_cast<const T&> (a);
450 const T& b_ = static_cast<const T&> (b);
451 if (! (a_ == b_))
452 erreur = 1;
453 return 1;
454 }
455 else
456 {
457 return 0;
458 }
459}
460
461/*! @brief renvoie 1 (sur tous les procs) si le parametre est identique sur tous les procs, sinon renvoie 0 (sur tous les procs)
462 *
463 */
464bool is_parallel_object(const Objet_U& obj)
465{
466 int erreur = 0;
468 {
469 DerObjU copie;
470 const int n = Process::nproc();
471 for (int i = 1; i < n; i++)
472 {
473 recevoir(copie, i, 67 /* tag */);
474 if (erreur)
475 continue; // On a deja trouve une erreur, on recoit les autres messages mais c'est tout...
476 const Objet_U& obj2 = copie.valeur();
477 if (obj2.que_suis_je() != obj.que_suis_je())
478 {
479 erreur = 1;
480 }
481 else
482 {
483 // L'operateur == n'est pas virtuel, on ne peut pas se contenter de comparer avec ==.
484 // Il faut appeler == pour le sous-type specifique de l'objet.
485 // L'ordre est important: d'abord le type le plus derive, puis sa classe de base.
486 if (compare<IntTab> (obj, obj2, erreur)) { /* Do nothing */ }
487 else if (compare<DoubleTab> (obj, obj2, erreur)) { /* Do nothing */ }
488 else if (compare<IntVect> (obj, obj2, erreur)) { /* Do nothing */ }
489 else if (compare<DoubleVect> (obj, obj2, erreur)) { /* Do nothing */ }
490 else if (compare<ArrOfInt> (obj, obj2, erreur)) { /* Do nothing */ }
491 else if (compare<ArrOfDouble> (obj, obj2, erreur)) { /* Do nothing */ }
492 else if (compare<Motcle> (obj, obj2, erreur)) { /* Do nothing */ }
493 else if (compare<Nom> (obj, obj2, erreur)) { /* Do nothing */ }
494 else
495 {
496 Cerr << "Internal error in is_parallel_objec() : it is not coded for " << obj.que_suis_je() << finl;
498 }
499 }
500 }
501 }
502 else
503 {
504 // On envoie un objet de type OWN_PTR..
505 DerObjU copie(obj);
506 envoyer(copie, 0, 67 /* tag */);
507 }
508
509 envoyer_broadcast(erreur, 0 /* pe source */);
510 return !erreur;
511}
512
513/*! @brief en mode comm_check_enabled(), verifie que le parametre a la meme valeur sur tous les processeurs.
514 *
515 * Ne fonctionne pas pour tous les types ! Pour l'instant ok pour Noms, Motcles et tableaux.
516 *
517 */
518void assert_parallel(const Objet_U& obj)
519{
521 return;
522
523 if (!is_parallel_object(obj))
524 {
525 Cerr << "Fatal error in assert_parallel(const Objet_U & obj): objects do not match, see log files" << finl;
526 Process::Journal() << "Error in assert_parallel(const Objet_U & obj)"
527 << "This processor has this object : " << obj.que_suis_je() << finl
528 << obj << finl;
531 }
532}
: Cette classe decrit un groupe de processeurs sur lesquels
Definition Comm_Group.h:40
static int check_enabled()
Definition Comm_Group.h:159
virtual void all_gather(const void *src_buffer, void *dest_buffer, int data_size) const =0
virtual void send(int pe, const void *buffer, int size, int tag) const =0
int nproc() const
Renvoie le nombre de processeurs dans le groupe *this.
Definition Comm_Group.h:190
int rank() const
Renvoie le rang du processeur local dans le groupe *this.
Definition Comm_Group.h:182
virtual void all_gatherv(const void *src_buffer, void *dest_buffer, int send_size, const int *recv_size, const int *displs) const =0
virtual void broadcast(void *buffer, int size, int pe_source) const =0
virtual void mp_collective_op(const double *x, double *resu, int n, Collective_Op op) const =0
virtual void all_to_all(const void *src_buffer, void *dest_buffer, int data_size) const =0
virtual void recv(int pe, void *buffer, int size, int tag) const =0
virtual void gather(const void *src_buffer, void *dest_buffer, int data_size, int root) const =0
: Classe outil utilisee exclusivement par Schema_Comm.
char * reserve_buffer(int bufsize)
classe Objet_U Cette classe est la classe de base des Objets de TRUST
Definition Objet_U.h:73
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
: Classe outil utilisee exclusivement par Schema_Comm.
const char * get_buffer()
static const Comm_Group & current_group()
renvoie une reference au groupe de processeurs actif courant
Definition PE_Groups.h:65
static double mp_min(double)
Definition Process.cpp:386
static double mp_max(double)
Definition Process.cpp:376
static Sortie & Journal(int message_level=0)
Renvoie un objet statique de type Sortie qui sert de journal d'evenements.
Definition Process.cpp:588
static int nproc()
renvoie le nombre de processeurs dans le groupe courant Voir Comm_Group::nproc() et PE_Groups::curren...
Definition Process.cpp:104
static void barrier()
Synchronise tous les processeurs du groupe courant (attend que tous les processeurs soient arrives a ...
Definition Process.cpp:136
static int me()
renvoie mon rang dans le groupe de communication courant.
Definition Process.cpp:125
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
static int je_suis_maitre()
renvoie 1 si on est sur le processeur maitre du groupe courant (c'est a dire me() == 0),...
Definition Process.cpp:86
void echange_taille_et_messages() const
Cette methode lance l'echange de donnees entre tous les processeurs.
Sortie & send_buffer(int num_PE) const
renvoie le buffer correspondant au processeur num_PE pour y entasser des donnees a envoyer.
void end_comm() const
Vide les buffers et libere les ressources: on a fini de lire les donnees recues dans les buffers.
Entree & recv_buffer(int num_PE) const
renvoie le buffer correspondant au processeur num_PE pour y lire les donnees recues.
void begin_comm() const
Reserve les buffers de comm pour une nouvelle communication.
void set_send_recv_pe_list(const ArrOfInt &send_pe_list, const ArrOfInt &recv_pe_list, const int me_to_me=0)
Definit la liste des processeurs a qui on va envoyer et de qui on va recevoir des donnees.
Represents a an array of int/int64/double/... values.
Definition TRUSTArray.h:81
_SIZE_ size_array() const
_TYPE_ * addr()
_TYPE_ * data()
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
: Tableau a n entrees pour n<= 4.
Definition TRUSTTab.h:31
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
_SIZE_ size() const
Definition TRUSTVect.tpp:45
const Objet_U & valeur() const
classe TRUST_Vector