Je sais que vous demandez une bibliothèque. Si vous n'en trouvez pas (::boggle: :, on croirait que le problème est résolu !), voici l'ébauche d'une solution :
Vous devriez pouvoir écrire un générateur de code [1] pour sérialiser les arbres/graphes sans prétraitement (d'exécution) assez simplement.
Vous devrez analyser la structure des nœuds ( typedef
), et écrivez les valeurs de données incluses de manière directe, mais traitez les pointeurs avec précaution.
-
Pour les pointeurs vers d'autres objets (ex. char *name;
) que vous connaître sont référencés de manière unique, vous pouvez sérialiser les données cibles directement.
-
Pour les objets qui peuvent être référencés plusieurs fois et pour les autres nœuds de votre arbre, vous devrez représenter la structure des pointeurs. Chaque objet se voit attribuer un numéro de sérialisation, qui est ce qui est écrit à la place du pointeur. Maintenez une structure de traduction entre la position actuelle de la mémoire et le numéro de sérialisation. Lorsque vous rencontrez un pointeur, vérifiez si un numéro lui a déjà été attribué, sinon, attribuez-lui un numéro et mettez cet objet en file d'attente pour la sérialisation.
La relecture nécessite également une étape de traduction nœud-#/emplacement en mémoire, et pourrait être plus facile à faire en deux passes : régénérer les nœuds avec les numéros de nœuds dans les slots de pointeurs (mauvais pointeur, attention) pour trouver où chaque nœud est placé, puis parcourir à nouveau la structure en fixant les pointeurs.
Je n'y connais rien en tpl, mais vous pouvez peut-être vous en servir.
Le format sur disque/réseau devrait probablement être encadré par des informations de type. Vous aurez besoin d'un système de mélange de noms.
[1] Racine utilise ce mécanisme pour fournir un support de sérialisation très flexible en C++.
Ajout tardif : Il me semble que ce n'est pas toujours aussi facile que je l'ai laissé entendre ci-dessus. Considérons la déclaration suivante (inventée et mal conçue) :
enum {
mask_none = 0x00,
mask_something = 0x01,
mask_another = 0x02,
/* ... */
mask_all = 0xff
};
typedef struct mask_map {
int mask_val;
char *mask_name;
} mask_map_t;
mask_map_t mask_list[] = {
{mask_something, "mask_something"},
{mask_another, "mask_another"},
/* ... */
};
struct saved_setup {
char* name;
/* various configuration data */
char* mask_name;
/* ... */
};
et supposons que nous initalisons struct saved_setup
afin que mask_name
points à mask_list[foo].mask_name
.
Quand nous allons sérialiser les données, que faisons-nous avec struct saved_setup.mask_name
?
Vous devrez faire attention à la conception de vos structures de données et/ou apporter une intelligence spécifique au processus de sérialisation.