Dans ce sous-chapitre, nous n'allons pas parler des modules puisque la majeure partie de ce qu'il y avait à dire a été abordé dans le sous-chapitre Exemple simple.
Ici, nous allons parler service, et plus précisément du service RNG. Nous n'allons pas parler de l'implémentation des différentes méthodes de l'interface, ce n'est pas le but de ce sous-chapitre. Donc, le fichier RNGService.cc
sera volontairement omis.
IRandomNumberGenerator.h
Voici l'interface utilisée par ce service :
#ifndef ARCANE_IRANDOMNUMBERGENERATOR_H
#define ARCANE_IRANDOMNUMBERGENERATOR_H
#include "arcane/utils/Array.h"
{
class ARCANE_CORE_EXPORT IRandomNumberGenerator
{
public:
virtual ~IRandomNumberGenerator() = default;
public:
virtual bool initSeed() = 0;
virtual bool initSeed(ByteArrayView seed) = 0;
virtual ByteConstArrayView viewSeed() = 0;
virtual ByteUniqueArray emptySeed() = 0;
virtual Integer neededSizeOfSeed() = 0;
virtual bool isLeapSeedSupported() = 0;
virtual ByteUniqueArray generateRandomSeed(Integer leap = 0) = 0;
virtual ByteUniqueArray generateRandomSeed(ByteArrayView parent_seed, Integer leap = 0) = 0;
virtual bool isLeapNumberSupported() = 0;
virtual Real generateRandomNumber(Integer leap = 0) = 0;
virtual Real generateRandomNumber(ByteArrayView seed, Integer leap = 0) = 0;
};
}
#endif
Déclarations des types utilisés dans Arcane.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
Il n'y a pas grand-chose à dire ici, c'est une interface assez classique. On a les premières lignes avec la licence et une courte description de l'interface (lignes 1-12). Ensuite, on a une classe avec des méthodes virtuelles égales à 0, ce qui en fait des méthodes virtuelles pures que l'on doit implémenter dans une implémentation.
`A noter cependant que les graines sont représentées par des tableaux de Bytes (ByteUniqueArray) et sont manipulées par des vues (ByteArrayView). Cela permet de rendre l'application indépendante de l'implémentation de Arcane::IRandomNumberGenerator
.
En effet, l'implémentation présente dans notre mini-app utilise des graines sur 64 bits (donc 8 octets) mais il se pourrait qu'une autre implémentation utilise des graines sur 32 bits. Donc on utilise des tableaux de tailles définis lors de l'exécution (le choix de l'implémentation étant faite dans le jeu de données, impossible de connaitre la taille d'une graine à la compilation).
RNG.axl
Voyons maintenant le .axl
:
<?xml version="1.0"?>
<service name="RNG" version="1.0" singleton="true">
<description>Jeu de données du service RNG</description>
<interface name="IRandomNumberGenerator" />
<variables>
</variables>
<options>
</options>
</service>
On peut voir que ça ressemble fortement à un .axl
de module.
<service name="RNG" version="1.0" singleton="true">
Ici, on a une nouveauté : singleton="true"
. Cette partie nous dit qu'il est possible d'utiliser ce service en tant que singleton.
<interface name="IRandomNumberGenerator" />
On donne à Arcane l'interface du service. En effet, comme on le verra après, la classe RNGService
n'hérite pas directement de l'interface Arcane::IRandomNumberGenerator
. C'est géré par le fichier généré RNG_axl.h
.
RNGService.h
Voici le header du service RNG :
#include <arcane/IRandomNumberGenerator.h>
#include "rng/RNG_axl.h"
class RNGService
: public ArcaneRNGObject
{
public:
: ArcaneRNGObject(sbi)
, m_seed(0)
{}
virtual ~RNGService() {};
public:
bool initSeed() override;
Integer neededSizeOfSeed() override;
bool isLeapSeedSupported() override { return false; };
bool isLeapNumberSupported() override { return false; };
Real generateRandomNumber(Integer leap) override;
Real generateRandomNumber(
ByteArrayView seed, Integer leap = 0)
override;
protected:
Real _rngSample(Int64* seed);
void _breakupUInt64(uint64_t uint64_in, uint32_t& front_bits, uint32_t& back_bits);
uint64_t _reconstructUInt64(uint32_t front_bits, uint32_t back_bits);
void _pseudoDES(uint32_t& lword, uint32_t& irword);
uint64_t _hashState(uint64_t initial_number);
protected:
Int64 m_seed;
const Integer m_size_of_seed = sizeof(Int64);
};
ARCANE_REGISTER_SERVICE_RNG(RNG, RNGService);
Structure contenant les informations pour créer un service.
Vue modifiable d'un tableau d'un type T.
Vue constante d'un tableau de type T.
Vecteur 1D de données avec sémantique par valeur (style STL).
Là aussi, c'est très semblable à un module. La plus grosse différence est au niveau des méthodes override. En effet, dans un module, on override les points d'entrées que l'on a défini dans le .axl
. Ici, dans ce service, on override les méthodes virtuelles de notre interface. Les services ne peuvent pas avoir de points d'entrées.
- Note
- Au niveau des
includes
, il faut s'assurer que l'interface déclarée dans le .axl
soit accessible par le .h
généré à partir du .axl
. Par exemple, ici, l'ordre des includes
est très important. Dans le .axl
, on déclare ceci : <interface name="IRandomNumberGenerator" />
Dans le fichier RNG_axl.h
qui sera généré, on obtiendra cela :
class ArcaneRNGObject
{
Classe de base de service lié à un sous-domaine.
Interface pour un générateur de nombre aléatoire.
Il faut donc inclure l'interface avant ce fichier : #include <arcane/IRandomNumberGenerator.h>
#include "rng/RNG_axl.h"