IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Ada Discussion :

Spécification de listes doublements chaînées génériques


Sujet :

Ada

  1. #1
    Invité
    Invité(e)
    Par défaut Spécification de listes doublements chaînées génériques
    Bonjour,
    Je suis amateur en programmation.
    Je souhaite manipuler du texte stocké dans des listes.
    Le code ci-dessous est la spécification de ma librairie.
    Je voudrais vérifier avec vous si cette spécification est bien cohérente, excepté pour la procédure "Insert_Before_Current" que je souhaite éventuellement transformer en "insert_after_current" parce que je ne comprends plus pourquoi insérer avant et pas après et que ça me semble plus pratique... Si vous pouviez m'éclairer.
    J'aurais souhaité savoir si j'oublie quelque chose d'essentiel et si vous aviez une librairie qui remplisse au moins les services que je spécifie ici, si vous vouliez bien la partager.
    Merci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    with Ada.Finalization;
    with Ada.Unchecked_deallocation;
    generic
       type T_Item is private;
       Null_Item : T_Item;
    package Generic_Doubly_Linked_Lists is
       type T_List Is limited private;
       function Length_Of (The_List : in T_List) return Integer;
       function Current_Content(The_List : in T_List) return T_Item;
       procedure Change_Current_Content(The_List:in out T_List;
                                Item : in T_Item);
       procedure To_Head (The_List : in out T_List);
       procedure To_Queue (The_List : in out T_List);
       procedure To_Next (The_List : in out T_List);
       procedure To_Predecessor (The_List : in out T_List);
       procedure Fission_At_Current (The_List : in out T_List; Rest : out T_list);
       function In_Queue (The_List : in T_List) return Boolean;
       function In_Head (The_List : in T_List) return Boolean;
       procedure Insert_Before_Current (The_List : in out T_List;
                                        Item : in T_Item);
       procedure Suppress_Current (The_List : in out T_List);
       procedure Empty (The_List : in out T_List);
    private
       type T_Node;
       type Node_Access is access T_Node;
       type T_Node is
          record
             Item : T_Item;
             Prev : Node_Access;
             Next : Node_Access;
          end record;
       type T_List is new Ada.Finalization.Limited_Controlled with
          record
             Head, Current   : Node_Access;
             Length : Natural := 0;
          end record;
      procedure free is new Ada.Unchecked_deallocation (T_Node, Node_Access);
      procedure Finalize(The_List : in out T_List) renames Empty;
    end Generic_Doubly_Linked_Lists;
    Dernière modification par Invité ; 20/03/2008 à 19h42. Motif: Correction du code

  2. #2
    Membre habitué
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 114
    Points : 139
    Points
    139
    Par défaut
    Pour les grandes lignes, je trouve cela pas mal.

    Après j'ai quelques remarques plus sur la forme :
    - ta liste n'est pas instantiable avec un type limité : c'est peut-être dommage.
    - à Quoi va servir Null_Item ?
    - Il est dommage que tu caches l'héritage : mais tu peux avoir de bonnes raisons.
    - Il ne faut pas confondre Empty & Finalize qui non pas le même but : le premier vider la liste, l'autre détruire physiquement la liste.
    - Essaie d'être moins verbeux sur le nom des procédures : inspire toi par exemple de llibrairies standard d'autres langages (Java, C++) afin d'avoir un langage commun ex : To_predecessor => Prev.
    - Dans le même ordre d'idée, plutot que The_List utilise This comme nom formel du paramètre.
    - Comme ton type est limité, propose une méthode Copy : ca peut servir.
    - Propose aussi de base un type Access sur une liste : ca évitera aux utilisateurs de le créer à chaque fois qu'ils en ont besoin.
    - Essaie de mettre ce que fait chaque procedure en commentaires : on parle de contrat, donc de programmation par contrats (si ca te dit rien va voir sur ) et ca t'aidera (et les utilisateurs) à bien désigner et utiliser ces bibliothèques.

    Voilà en vrac mes remarques : tu prends ce que tu veux .
    Bon courage et n'hésite pas à solliciter .

  3. #3
    Invité
    Invité(e)
    Par défaut
    Bonjour, merci pour ta réponse.
    Citation Envoyé par Lowelace Voir le message
    Pour les grandes lignes, je trouve cela pas mal.
    J'ai en parti pompé, et un peu d'expérience, mais ça n'a pas l'air parfait. Je souhaiterai ne pas avoir à revenir sur cette liste générique.
    Citation Envoyé par Lowelace Voir le message
    Après j'ai quelques remarques plus sur la forme :
    Citation Envoyé par Lowelace Voir le message
    - ta liste n'est pas instantiable avec un type limité : c'est peut-être dommage.
    Suffirait-il que je déclare de le type générique "limited" ? Pourais-je l'instancier avec un type non limité ? (je dois avoir la réponse dans un bouquin).
    Citation Envoyé par Lowelace Voir le message
    - à Quoi va servir Null_Item ?
    Je l'ai supprimé en fait pour le moment.
    Citation Envoyé par Lowelace Voir le message
    - Il est dommage que tu caches l'héritage : mais tu peux avoir de bonnes raisons.
    C'est à dire ?
    Citation Envoyé par Lowelace Voir le message
    - Il ne faut pas confondre Empty & Finalize qui non pas le même but : le premier vider la liste, l'autre détruire physiquement la liste.
    Vu l'implémentation de Empty ci-dessous... Y a t-il une erreur quelque part ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    procedure Empty (The_List : in out T_List) is
          Old_Pointer : Node_Access;
       begin
     
          while The_List.Head /= null loop
             Old_Pointer := The_List.Head;
             The_List.Head := The_List.Head.Next;
             Free (Old_Pointer);
          end loop;
          The_List.length := 0;
          The_List.Current := null;
          The_List.Position := 0;
       end Empty;
    Citation Envoyé par Lowelace Voir le message
    - Essaie d'être moins verbeux sur le nom des procédures : inspire toi par exemple de llibrairies standard d'autres langages (Java, C++) afin d'avoir un langage commun ex : To_predecessor => Prev.
    Euh, non, pourquoi fair encore moins explicite ...
    J'ai apris que plus c'est long plus c'est bon
    Citation Envoyé par Lowelace Voir le message
    - Dans le même ordre d'idée, plutot que The_List utilise This comme nom formel du paramètre.
    Ah oui +1
    Citation Envoyé par Lowelace Voir le message
    - Comme ton type est limité, propose une méthode Copy : ca peut servir.
    Ok !
    Citation Envoyé par Lowelace Voir le message
    - Propose aussi de base un type Access sur une liste : ca évitera aux utilisateurs de le créer à chaque fois qu'ils en ont besoin.
    Ok !
    Citation Envoyé par Lowelace Voir le message
    - Essaie de mettre ce que fait chaque procedure en commentaires : on parle de contrat, donc de programmation par contrats (si ca te dit rien va voir sur ) et ca t'aidera (et les utilisateurs) à bien désigner et utiliser ces bibliothèques.
    Ah, les commentaires... un minimum, oui c'est pas mon fort. Je vais faire un effort. Désolé.
    Citation Envoyé par Lowelace Voir le message
    Voilà en vrac mes remarques : tu prends ce que tu veux .
    Bon courage et n'hésite pas à solliciter .
    Oui, super.
    Merci encore.

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 114
    Points : 139
    Points
    139
    Par défaut
    Pour le type limité comme paramètre générique, effectivement tu pourras instancier avec un type non limité. Par contre, il faut ajouter une fonction Copy qui te permettra de faire l'affectation d'un Item dans un autre au niveau de ta liste. Çà alourdit l'instance de la liste, mais c'est plus générique.
    Par contre, là où c'est pénible,c'est pour les type non limité, il faut encapsuler le := dans une procédure.

    Tu hérites de Ada.Finalization.Limited_Controlled, Hors cet héritage n'est visible que dans la partie privée. Donc non accessible à l'utilisateur .
    Cet héritage t'ajoute des fonctionnalités supplémentaires (c'est fait pour çà) que donc tu caches. Est-ce bien nécessaire ?

    Plus c'est long, Plus c'est bon : Ok . Mais à petites doses, après çà rend . Une bibliothèque est faite pour être utilisée de manière intensive, donc elle doit être "ergonomique". De plus, pour des bibliothèques que je qualifie de "standard", pas besoin de s'étendre. Mais bon,ce n'est que mon avis .

    Ton implémentation de Empty, qui vide une liste, est un peu dangereuse. Tu libères de la mémoire (Free sur tes items). Qui te dis que quelqu'un ne pointe pas au même endroit, par exemple suite à l'appel de Fission :
    - tu copies ta liste pour la sauvegarder (si la copie n'est pas profonde).
    - tu coupes ta liste en deux avec Fission.
    - tu vides ta tête de liste et , tu pourris ta sauvegarde car tu as détruit la mémoire de tes éléments sauvegardés.
    Il faut à mon avis séparé les concepts : Liste vide et Libération de la mémoire.

    Tiens, pourquoi ne pas ajouter une fonction de concaténation ?

  5. #5
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Lowelace Voir le message
    Pour le type limité comme paramètre générique, effectivement tu pourras instancier avec un type non limité. Par contre, il faut ajouter une fonction Copy qui te permettra de faire l'affectation d'un Item dans un autre au niveau de ta liste. Çà alourdit l'instance de la liste, mais c'est plus générique.
    C'est bien mon objectif, et me semble presque à ma porté car, je ne saisi pas la suite...
    Pour l'affectation de type limité donc, je fourni une procédure d'affectation à la liste. Mais pour les type non limité ... ça donne quoi ?
    Citation Envoyé par Lowelace Voir le message
    Par contre, là où c'est pénible,c'est pour les type non limité, il faut encapsuler le := dans une procédure.
    Tu n'aurais pas un exemple ?
    Citation Envoyé par Lowelace Voir le message
    Tu hérites de Ada.Finalization.Limited_Controlled, Hors cet héritage n'est visible que dans la partie privée. Donc non accessible à l'utilisateur .
    Cet héritage t'ajoute des fonctionnalités supplémentaires (c'est fait pour çà) que donc tu caches. Est-ce bien nécessaire ?
    Alors, en fait, j'ai pompé sur une implémentation de Christian Carrez, auteur de "Structure de données" aux éditions InterEdition et je pense que cette procédure est utilisé dans dans des enfants du paquetage principal. En effet pour le moment elle n'a pas d'utilité.
    Citation Envoyé par Lowelace Voir le message
    Plus c'est long, Plus c'est bon : Ok . Mais à petites doses, après çà rend . Une bibliothèque est faite pour être utilisée de manière intensive, donc elle doit être "ergonomique". De plus, pour des bibliothèques que je qualifie de "standard", pas besoin de s'étendre. Mais bon,ce n'est que mon avis .
    Ok, si tu insiste, je vais œuvrer dans ce sens.
    Citation Envoyé par Lowelace Voir le message
    Ton implémentation de Empty, qui vide une liste, est un peu dangereuse. Tu libères de la mémoire (Free sur tes items). Qui te dis que quelqu'un ne pointe pas au même endroit, par exemple suite à l'appel de Fission :
    - tu copies ta liste pour la sauvegarder (si la copie n'est pas profonde).
    - tu coupes ta liste en deux avec Fission.
    - tu vides ta tête de liste et , tu pourris ta sauvegarde car tu as détruit la mémoire de tes éléments sauvegardés.
    Il faut à mon avis séparé les concepts : Liste vide et Libération de la mémoire.
    Ok, je vais voir ça !
    Citation Envoyé par Lowelace Voir le message
    Tiens, pourquoi ne pas ajouter une fonction de concaténation ?
    Oui, alors comme pour la procédure de copie de liste, n'est-il préférable de faire ça dans un paquetage enfant ?

    Merci.

  6. #6
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par jovalise Voir le message

    Oui, alors comme pour la procédure de copie de liste, n'est-il préférable de faire ça dans un paquetage enfant ?
    Je demande ça, mais je ne vois pas comment c'est possible pour le moment. Je fatigue un peu en fin de journée ....

    A+ Merci encore.

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 114
    Points : 139
    Points
    139
    Par défaut
    Voici un exemple un type non limité :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
     
    generic
     
    type Item is limited private;
    with procedure Copy(Destination : out Item; Source : in Item);
     
    package Liste_Doublement_Chainee is
     ...
    End;
     
    procedure Copy(Destination : out Float; Source : in Float);
     
    package List_Float is new Liste_Doublement_Chainee(Float, Copy);
     
    procedure Copy(Destination : out Float; Source : in Float) is
    begin
       Destination := Source;
    end Copy;
    Pour ce qui est de mettre copy et concatenation dans un paquetage enfant, il faut voir. Pour ma part, je mets dans un paquetage enfant que les extensions "marginales" ou non strictement nécessaires : Copy n'est pas à mon avis dans cette catégorie, Concatenation est du même niveau que Fission. Donc, il faut avoir une approche cohérente. C'est à toi de voir.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
     
    package Liste_doublement_chainee.Extensions is
     
    procedure Copy(Destination : out T_list; Source : in T_list);
     
    end;
     
    package body  Liste_doublement_chainee.Extensions is
     
    procedure Copy(Destination : out T_list; Source : in T_list) is
    begin
     
    Destination.length := Source.Length;
     
    ...
    end;
    end;

  8. #8
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Lowelace Voir le message

    Pour ce qui est de mettre copy et concatenation dans un paquetage enfant, il faut voir. Pour ma part, je mets dans un paquetage enfant que les extensions "marginales" ou non strictement nécessaires : Copy n'est pas à mon avis dans cette catégorie, Concatenation est du même niveau que Fission. Donc, il faut avoir une approche cohérente. C'est à toi de voir.
    Oui, alors je vais présenter copy et concatener dans dans le paquetage principal.

    Pour les exemples, c'est surtout l'utilisation de la liste avec des types non limités dans le cas ou j'accepte des types limités que j'aurais aimé voir ce que ça donne.

  9. #9
    Membre habitué
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 114
    Points : 139
    Points
    139
    Par défaut
    Qu'entends-tu par utilisation ? Si c'est l'instanciation du générique regarde mon message précédent dans la 1ère partie .

    Sinon il n'y a pas de différence d'utilisation du paquetage instancié avec un type limité ou non limité .

  10. #10
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Lowelace Voir le message
    Par contre, là où c'est pénible,c'est pour les type non limité, il faut encapsuler le := dans une procédure.
    Oui, ici, tu parle d'encapsulation dans le cas d'une utilisation avec des type non limités.

    Mais c'est peut-être bateau ... je verrai ça dans le week end.

  11. #11
    Membre habitué
    Profil pro
    Inscrit en
    Janvier 2008
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2008
    Messages : 114
    Points : 139
    Points
    139
    Par défaut
    Citation Envoyé par Lowelace Voir le message
    Voici un exemple un type non limité :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    procedure Copy(Destination : out Float; Source : in Float);
    
    package List_Float is new Liste_Doublement_Chainee(Float, Copy);
    
    procedure Copy(Destination : out Float; Source : in Float) is
    begin
       Destination := Source; -- encapsulation de := 
    end Copy;

  12. #12
    Invité
    Invité(e)
    Par défaut
    Merci Lowelace.
    Rien de sorcier apparemment.
    A+ Bon week end !

Discussions similaires

  1. Réponses: 10
    Dernier message: 16/11/2010, 09h26
  2. Réponses: 9
    Dernier message: 14/01/2007, 17h09
  3. Listes doublement chaînées
    Par nicolas66 dans le forum C++
    Réponses: 5
    Dernier message: 19/11/2005, 12h17
  4. Liste doublement chaînée
    Par garf dans le forum Langage
    Réponses: 3
    Dernier message: 27/09/2005, 09h33

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo