• Aucun résultat trouvé

2.1 Arch´ etype de donn´ ees

2.1.3 Implantation

Nous venons de voir dans la section pr´ec´edente comment l’arch´etype des corps finis d´efinit une interface de donn´ees compilable. N´eanmoins, cette implantation n’est pas suffisante pour d´ecrire le mod`ele complet de l’arch´etype des corps finis. Dans la partie 2.1.1 nous avons vu que le mod`ele de base encapsule un type d’´el´ement et un type de g´en´erateur al´eatoire. Bien que chacun de ces types poss`ede un arch´etype d´efinissant une interface compilable, suivant le mˆeme mod`ele que celui d´ecrit dans la figure 2.3, l’interaction de ces diff´erents arch´etypes n’est pas imm´ediate.

En effet, la construction d’´el´ements abstraits au sein de l’arch´etype des corps finis ne peut se faire que si l’arch´etype connaˆıt le type concret de ces ´el´ements, ce qui n’est pas le cas. Il en est de mˆeme pour les g´en´erateurs al´eatoires.

Une solution propos´ee dans la biblioth`eque LinBox est de stocker les types dynamiques des

´

el´ements abstraits et des g´en´erateurs abstraits. Cela se traduit en pratique par l’int´egration dans l’arch´etype d’un pointeur sur unElementAbstractet d’un pointeur sur un RandIterAbstract.

Ces pointeurs sont instanci´es lors de la construction de l’arch´etype `a partir d’un corps fini concret (voir code 2.1 lignes 15, 16, 26 et 27). Grˆace `a ces pointeurs et aux fonctions clone(), l’arch´etype peut donc g´en´erer des ´el´ements abstraits relatifs au corps fini sur lequel est instanci´e l’arch´etype. C’est d’ailleurs `a partir de ce m´ecanisme que la fonction initest capable d’allouer de la m´emoire pour des ´el´ements abstraits (voir code 2.1 ligne 70). Toutefois, la fonctionclone n’est pas suffisante pour allouer un arch´etype de g´en´erateur al´eatoire. En plus du corps finis, le g´en´erateur n´ecessite une graine d’al´ea et la taille de l’´echantillon des ´el´ements al´eatoires. Dans ce cas pr´ecis, la fonctioncloneest remplac´ee par la fonctionconstructqui permet la construction d’un g´en´erateur abstrait param´etrable (voir code 2.3 ligne 14). Le pointeur _randiter_ptr de la classe FieldArchetype sert uniquement `a r´ecup´erer la fonctionconstruct `a partir du type dynamique du g´en´erateur associ´e au corps fini instanci´e dans l’arch´etype.

L’utilisation de ces deux pointeurs pourrait cependant ˆetre remplac´ee par deux fonctions virtuelles construct_elem et construct_randiter d´efinies dans la classe FieldAbstract. La construction dynamique des ´el´ements et des g´en´erateurs serait alors directement attach´ee au bon type de corps finis. Cette solution semble raisonnable du fait que les types de ces derniers sont d´ej`a encapsul´es dans le mod`ele des corps finis. De plus, cela permettrait une gestion plus trans-parente de l’arch´etype. N´eanmoins, cette solution entraˆıne une d´ependance entre les arch´etypes qui peut s’av´erer gˆenante

Nous avons vu dans la section pr´ec´edente que l’utilisation de l’enveloppe pouvait ˆetre inutile si le corps utilis´e d´erive directement de l’interface abstraite. Cette option est prise en consid´ e-ration dans la construction de l’arch´etype. La solution propos´ee consiste `a utiliser une fonction construct qui utilise l’enveloppe uniquement si le corps ne d´erive pas de la classe abstraite.

Cette fonction est d´efinie en deux exemplaires et utilise une sp´ecialisation d’un pointeur void pour r´ecup´erer la hi´erarchie de classe du corps utilis´e (voir code 2.1 lignes 11 et 23).

Enfin, le dernier point important de l’interaction entre les diff´erents arch´etypes est la d´

efi-2.1. Arch´etype de donn´ees 35 nition des op´erations sur les ´el´ements du corps. Ces fonctions sont d´efinies dans l’arch´etype au travers de l’arch´etype des ´el´ements. Afin d’implanter ces fonctions directement `a partir d’appels de fonction de l’interface abstraite, il faut pouvoir acc´eder au type abstrait des ´el´ements dans l’arch´etype des corps finis. Cela est possible en pratique grˆace `a la d´efinition mutuelle des ar-ch´etypes en tant qu’amis `a partir du caract`ere friend (voir code 2.2 lignes 5 et 6).

Soient Field1 etField2 deux mod`eles de corps finis conforment `a l’arch´etype de la biblio-th`eque LinBox, on peut alors d´efinir l’exemple suivant pour l’utilisation de l’arch´etype.

std :: vector < E l e m e n t A r c h e t y p e > g e n v e c t o r ( c o n s t F i e l d A r c h e t y p e & F ,

s i z e _ t n ,

s i z e _ t sample ,

s i z e _ t se ed )

{

std :: vector < E l e m e n t A r c h e t y p e > u ( n );

std :: vector < E l e m e n t A r c h e t y p e >:: i t e r a t o r pu = u . b e g i n ();

R a n d I t e r A r c h e t y p e G ( F , sample , se ed );

for (; pu != u . end (); ++ pu ){

F . ini t (* pu );

G . r a n d o m (* pu );

}

r e t u r n u ; }

int ma in (){

F i e l d 1 F1 ( 1 7 ) ; F i e l d 2 F2 ( 1 0 1 ) ;

F i e l d A r c h e t y p e FA1 (& F1 ) , FA2 (& F2 );

std :: vector < E l e m e n t A r c h e t y p e > u1 , u2 ; u1 = g e n v e c t o r ( FA1 , 1 0 0 , 1 7 , 1 2 3 4 5 6 7 8 9 ) ; u2 = g e n v e c t o r ( FA2 , 1 0 0 , 1 0 1 , 9 8 7 6 5 4 3 2 1 ) ; }

Cet exemple montre qu’on peut proposer une fonctiongenvector qui est `a la fois g´en´erique et compilable. La fonctiongenvector est compilable car elle est d´efinie `a partir de l’arch´etype et de types de base qui sont connus `a la compilation. Cette fonction est g´en´erique du fait des propri´et´es polymorphes de l’arch´etype. En pratique, il suffit d’instancier des arch´etypes `a partir de corps finis concrets, ici les arch´etypeFA1 etFA2pour les corps concretsF1 etF2. L’appel de la fonctiongenvector `a partir de ces arch´etypes permet de g´en´erer des vecteurs al´eatoires `a la fois dansF1 et dansF2.

Ce type de code en compilation s´epar´ee est impossible `a la fois pour des param`etrestemplate et pour des interfaces abstraites. Il est clair qu’en utilisant des param`etrestemplateon ne pourrait pas compiler la fonctiongenvectorsans pr´eciser les typesField1etField2. Par contre, `a partir de classes abstraites on ne pourrait pas g´en´erer les vecteursu1et u2 car la STL n´ecessite que les objets des conteneurs poss`edent des constructeurs, ce qui n’est pas le cas des objets abstraits.

Une alternative possible serait d’utiliser des vecteurs de pointeurs mais on voit tout de suite que la gestion m´emoire des ´el´ements alourdirait consid´erablement le code `a d´efinir.

Code 2.1 – Arch´etype des corps finis

c l a s s F i e l d A r c h e t y p e { private:

5 mutable F i e l d A b s t r a c t f i e l d p t r ; mutable E l e m e n t A b s t r a c t e l e m p t r ; mutable R a n d I t e r A b s t r a c t r a n d i t e r p t r ; // c o n s t r u c t o r from a F i e l d w h i c h i n h e r i t s 10 // from F i e l d A b s t r a c t ( E n v e l o p e i s n o t n e e d e d )

template<c l a s s F i e l d>

void c o n s t r u c t o r ( F i e l d A b s t r a c t t r a i t s , F i e l d ∗F) { f i e l d p t r = new F i e l d (∗F ) ;

e l e m p t r = new typename F i e l d : : Element ( ) ; 15 r a n d i t e r p t r = new typename F i e l d : : R a n d I t e r (∗F ) ;

}

// c o n s t r u c t o r from a F i e l d w h i c h d o e s n o t i n h e r i t // from F i e l d A b s t r a c t ( E n v e l o p e i s n e e d e d )

20 template<c l a s s F i e l d>

void c o n s t r u c t o r (void t r a i t s , F i e l d ∗F) { f i e l d p t r = new F i e l d E n v e l o p e<F i e l d> (∗F ) ; e l e m p t r = new ElementEnvelope<F i e l d>( ) ; r a n d i t e r p t r = new R a n d I t e r E n v e l o p e<F i e l d> (∗F ) ;

25 }

public:

typedef E le me ntAr che ty p e Element ; typedef R a n d I t e r A r c h e t y p e R a n d I t e r ; 30

// c o n s t r u c t o r o f f i e l d a r c h e t y p e template <c l a s s F i e l d>

F i e l d A r c h e t y p e ( F i e l d f ){ c o n s t r u c t o r ( f , f ) ;

35 }

// c op y c o n s t r u c t o r

F i e l d A r c h e t y p e (const F i e l d A r c h e t y p e &F) {

i f (F . f i e l d p t r != 0 ) f i e l d p t r = F . f i e l d p t r>c l o n e ( ) ; 40 i f (F . e l e m p t r != 0 ) e l e m p t r = F . e l e m p t r>c l o n e ( ) ;

i f ( F r a n d i t e r p t r != 0 ) r a n d i t e r p t r = F . r a n d i t e r p t r>c l o n e ( ) ; }

// d e s t r u c t o r

45 ˜ F i e l d A r c h e t y p e (void) {

i f ( f i e l d p t r != 0 ) d ele t e f i e l d p t r ; i f ( e l e m p t r != 0 ) d ele t e e l e m p t r ; i f ( r a n d i t e r p t r != 0 ) d ele t e r a n d i t e r p t r ; }

50

// a s s i g n e m e n t o p e r a t o r

F i e l d A r c h e t y p e &operator= (const F i e l d A r c h e t y p e &F) { i f (t h i s != &F) {

i f ( f i e l d p t r != 0 ) d e le t e f i e l d p t r ; 55 i f ( e l e m p t r != 0 ) d e le t e e l e m p t r ;

i f ( r a n d i t e r p t r != 0 ) d e le t e r a n d i t e r p t r ;

2.1. Arch´etype de donn´ees 37

i f (F . f i e l d p t r != 0 ) f i e l d p t r = F . f i e l d p t r>c l o n e ( ) ; i f (F . e l e m p t r != 0 ) e l e m p t r = F . e l e m p t r>c l o n e ( ) ; i f ( F r a n d i t e r p t r != 0 ) r a n d i t e r p t r = F . r a n d i t e r p t r>c l o n e ( ) ;

60 }

}

// i n i t i a l i z a t i o n o f e l e m e n t s a r c h e t y p e o v e r t h e f i e l d a r c h e t y p e Element & i n i t ( Element &x , const i n t e g e r &y ) const {

65 i f ( x . e l e m p t r != 0 ) d e le t e x . e l e m p t r ; x . e l e m p t r = e l e m p t r>c l o n e ( ) ;

f i e l d p t r>i n i t (x . e l e m p t r , y ) ; return x ;

} 70

// a d d i t i o n o f e l e m e n t s a r c h e t y p e Element& add ( Element &x ,

const Element &y ,

const Element &z ) const {

75 f i e l d p t r>add (x . e l e m p t r , ∗y . e l e m p t r , ∗z . e l e m p t r ) ; return x ;

} };

Code 2.2 – Arch´etype des ´el´ements

c l a s s E le me ntAr che ty p e { private:

5 f r i e n d c l a s s F i e l d A r c h e t y p e ; f r i e n d c l a s s R a n d I t e r A b s t r a c t ; mutable E l e m e n t A b s t r a c t e l e m p t r ; public:

10 // d e f a u l t c o n s t r u c t o r

E le me ntAr che ty p e (void) { e l e m p t r =0;}

// c op y c o n s t r u c u t o r

E le me ntAr che ty p e (const E le me ntAr che ty pe &a ) {

15 i f ( a . e l e m p t r != 0 ) e l e m p t r = a . e l e m p t r>c l o n e ( ) ; e l s e e l e m p t r =0;

}

// d e s t r u c t o r

20 ˜ E le me ntAr che ty pe (void) {

i f ( e l e m p t r != 0 ) d e le t e e l e m p t r ; }

// a f f e c t a t i o n o p e r a t o r

25 E le me ntAr che ty p e &operator= (const E le me ntAr che ty pe &a ) { i f (t h i s != &a ) {

i f ( e l e m p t r != 0 ) d e le t e e l e m p t r ;

i f ( a . e l e m p t r != 0 ) e l e m p t r = a . e l e m p t r>c l o n e ( ) ; }

30 return t h i s; }

};

Code 2.3 – Arch´etype des g´en´erateurs al´eatoires

c l a s s R a n d I t e r A r c h e t y p e { private:

5 mutable R a n d I t e r A b s t r a c t r a n d i t e r p t r ; public:

typedef E le me ntAr che ty p e Element ;

10 // c o n s t r u c t o r from a f i e l d a r c h e t y p e , a s i z e o f s a m p l i n g , and a s e e d R a n d I t e r A r c h e t y p e (const F i e l d A r c h e t y p e &F ,

const i n t e g e r &s i z e =0 , const i n t e g e r &s e e d =0) {

15 r a n d i t e r p t r=F . r a n d i t e r p t r>c o n s t r u c t (∗F . f i e l d p t r , s i z e , s e e d ) ; }

// c op y c o n s t r u c t o r

R a n d I t e r A r c h e t y p e (const R a n d I t e r A r c h e t y p e &R) 20 {

i f ( R . r a n d i t e r p t r != 0 )

r a n d i t e r p t r = R . r a n d i t e r p t r>c l o n e ( ) ; }

25 // d e s t r u c t o r

˜ R a n d I t e r A r c h e t y p e (void) {d ele t e r a n d i t e r p t r ;} // a s s i g n e m e n t o p e r a t o r

R a n d I t e r A r c h e t y p e &operator= (const R a n d I t e r A r c h e t y p e &R) 30 {

i f (t h i s != &R) {

i f ( r a n d i t e r p t r != 0 ) d e le t e r a n d i t e r p t r ;

i f (R . r a n d i t e r p t r != 0 ) r a n d i t e r p t r= R . r a n d i t e r p t r>c l o n e ( ) ; }

35 return t h i s; }

Element &random ( Element &a ) const {

40 r a n d i t e r p t r>random (∗a . e l e m p t r ) ; return a ;

} };