Structure - Duppliquer un champ

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Structure - Duppliquer un champ

Message par Ollivier »

J'ai dû looper un épisode avec les structures...

Si je créée une structure:

Code : Tout sélectionner

Structure ID
   Nom.S
   Prenom.S
   Adresse.S
EndStructure
Si j'alloue un tableau comme suit:

Code : Tout sélectionner

Dim Perso.ID(99)
M'est-il possible de duppliquer des données d'un Perso(Source) à un Perso(Destination)?

Code : Tout sélectionner

Structure ID
   Nom.S
   Prenom.S
   Adresse.S
EndStructure

   Dim Perso.ID(99)

   Perso(0)\Nom = "Dupont"
   Perso(0)\Prenom = "Jack"
   Perso(0)\Adresse = "3 Rue des stockosses 25000 Fleury"

   ;La ligne qui couine...
   Perso(1) = Perso(0)

   ;...Et qui équivaudrait à ça:
   Perso(1)\Nom = Perso(0)\Nom
   Perso(1)\Prenom = Perso(0)\Prenom
   Perso(1)\Adresse = Perso(0)\Adresse
Guimauve
Messages : 1015
Inscription : mer. 11/févr./2004 0:32
Localisation : Québec, Canada

Message par Guimauve »

Pour une structure, tu n'a pas le choix que de copier de champs à champs.

Code : Tout sélectionner

Structure ID
   Nom.S
   Prenom.S
   Adresse.S
EndStructure

   Dim Perso.ID(99)

   Perso(0)\Nom = "Dupont"
   Perso(0)\Prenom = "Jack"
   Perso(0)\Adresse = "3 Rue des stockosses 25000 Fleury"

   Perso(1)\Nom = Perso(0)\Nom
   Perso(1)\Prenom = Perso(0)\Prenom
   Perso(1)\Adresse = Perso(0)\Adresse 
On peut faire une série de macro pour rendre le code plus facile à lire.

Code : Tout sélectionner

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Déclaration de la Structure <<<<<

Structure ID
  
  Nom.s
  Prenom.s
  Adresse.s
  
EndStructure

; <<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Les mutateurs <<<<<

Macro SetIDNom(IdentifiantA, P_Nom)
  
  IdentifiantA\Nom = P_Nom
  
EndMacro

Macro SetIDPrenom(IdentifiantA, P_Prenom)
  
  IdentifiantA\Prenom = P_Prenom
  
EndMacro

Macro SetIDAdresse(IdentifiantA, P_Adresse)
  
  IdentifiantA\Adresse = P_Adresse
  
EndMacro

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Les observateurs <<<<<

Macro GetIDNom(IdentifiantA)
  
  IdentifiantA\Nom
  
EndMacro

Macro GetIDPrenom(IdentifiantA)
  
  IdentifiantA\Prenom
  
EndMacro

Macro GetIDAdresse(IdentifiantA)
  
  IdentifiantA\Adresse
  
EndMacro

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< L'opérateur Update <<<<<

Macro UpdateID(IdentifiantA, P_Nom, P_Prenom, P_Adresse)
  
  SetIDNom(IdentifiantA, P_Nom)
  SetIDPrenom(IdentifiantA, P_Prenom)
  SetIDAdresse(IdentifiantA, P_Adresse)
  
EndMacro

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< L'opérateur Copy : A = Source : B = Destination <<<<<

Macro CopyID(IdentifiantA, IdentifiantB)
  
  SetIDNom(IdentifiantB, GetIDNom(IdentifiantA))
  SetIDPrenom(IdentifiantB, GetIDPrenom(IdentifiantA))
  SetIDAdresse(IdentifiantB, GetIDAdresse(IdentifiantA))

EndMacro

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< L'opérateur Swap <<<<<

Macro SwapID(IdentifiantA, IdentifiantB)
  
  Swap GetIDNom(IdentifiantA), GetIDNom(IdentifiantB)
  Swap GetIDPrenom(IdentifiantA), GetIDPrenom(IdentifiantB)
  Swap GetIDAdresse(IdentifiantA), GetIDAdresse(IdentifiantB)
  
EndMacro

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Macro de déboguage <<<<<

Macro DebugID(IdentifiantA)
  
  Debug GetIDNom(IdentifiantA)
  Debug GetIDPrenom(IdentifiantA)
  Debug GetIDAdresse(IdentifiantA)
  
EndMacro

; <<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< Démonstration <<<<<

Dim Perso.ID(5)

UpdateID(Perso(0), "Dupont", "Jack", "3 Rue des stockosses 25000 Fleury")

For Index = 1 To 5
  CopyID(Perso(0), Perso(Index))
Next 

For Index = 0 To 5
  DebugID(Perso(Index))
  Debug ""
Next 

; <<<<<<<<<<<<<<<<<<<<<<<<<<
; <<<<< FIN DU FICHIER <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<<<<
A+
Guimauve
Dernière modification par Guimauve le dim. 19/août/2007 15:40, modifié 1 fois.
Anonyme

Message par Anonyme »

Testé sous linux :

Code : Tout sélectionner

Structure ID
   Nom.S
   Prenom.S
   Adresse.S
EndStructure

   Dim Perso.ID(99)

   Perso(0)\Nom = "Dupont"
   Perso(0)\Prenom = "Jack"
   Perso(0)\Adresse = "3 Rue des stockosses 25000 Fleury"

   ;La ligne qui couine...
   ;Perso(1) = Perso(0)
   CopyMemory(Perso(0),Perso(1),SizeOf(ID))


   ;...Et qui équivaudrait à ça:
   Debug Perso(1)\Nom 
   Debug Perso(1)\Prenom 
   Debug Perso(1)\Adresse 


@++ :wink:
Avatar de l’utilisateur
Chris
Messages : 3731
Inscription : sam. 24/janv./2004 14:54
Contact :

Message par Chris »

Sinon, tu peux faire ça...

Code : Tout sélectionner

Structure ID
  Nom.S
  Prenom.S
  Adresse.S
EndStructure

Dim Perso.ID(99)

 Perso(0)\Nom = "Dupont"
 Perso(0)\Prenom = "Jack"
 Perso(0)\Adresse = "3 Rue des stockosses 25000 Fleury"

   ;La ligne qui couine...
;Perso(1) = Perso(0)

PokeS(Perso(1), PeekS(Perso(0)))
PokeS(Perso(1)+4, PeekS(Perso(0)+4))
PokeS(Perso(1)+8, PeekS(Perso(0)+8))


Debug Perso(1)\Nom
Debug Perso(1)\Prenom
Debug Perso(1)\Adresse

   ;...Et qui équivaudrait à ça:
; Perso(1)\Nom = Perso(0)\Nom
; Perso(1)\Prenom = Perso(0)\Prenom
; Perso(1)\Adresse = Perso(0)\Adresse
... mais t'es pas plus avancé :lol:
Guimauve
Messages : 1015
Inscription : mer. 11/févr./2004 0:32
Localisation : Québec, Canada

Message par Guimauve »

Je suis désolé Cpl.Bator mais faire un CopyMemory() semble fonctionner mais ce n'est pas vrai. La seule chose que ça fait c'est de copier les pointeurs sur les chaines de caractère. Regarde le code suivant pour comprendre :

Code : Tout sélectionner

Structure ID
  Nom.S
  Prenom.S
  Adresse.S
EndStructure

Dim Perso.ID(99)

Perso(0)\Nom = "Dupont"
Perso(0)\Prenom = "Jack"
Perso(0)\Adresse = "3 Rue des stockosses 25000 Fleury"

   ;La ligne qui couine...
   ;Perso(1) = Perso(0)

For Index = 1 To 5
  CopyMemory(Perso(0),Perso(Index),SizeOf(ID))
Next 

   ;...Et qui équivaudrait à ça:

; Debug Perso(1)\Nom
; Debug Perso(1)\Prenom
; Debug Perso(1)\Adresse


Perso(0)\Nom = "Dupond"
Perso(0)\Prenom = "Patrick"
Perso(0)\Adresse = "2020 rue du fin fin"

For Index = 0 To 5
  
  Debug Perso(Index)\Nom
  Debug Perso(Index)\Prenom
  Debug Perso(Index)\Adresse
  Debug ""
  
Next
A+
Guimauve
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Merci Cpl :D

ça marche sous XP aussi. :D
C'est nickel chrome cette méthode!

8O EDIT: Oups, parlé trop vite!
En tout cas SizeOf(ID), ça m'avance mieux que SizeOf(Perso), erreur sur laquelle je suis resté scotché pendant une bonne demi-heure.

@Guimauve

J'essaye de comprendre la coucougnette. ?
Dernière modification par Ollivier le dim. 19/août/2007 16:04, modifié 1 fois.
Avatar de l’utilisateur
Chris
Messages : 3731
Inscription : sam. 24/janv./2004 14:54
Contact :

Message par Chris »

Guimauve a raison.

Ca ne marche pas. :?
Lna
Messages : 181
Inscription : mar. 21/juin/2005 11:11

Message par Lna »

Le copymemory serait valable pour des types non string.
Il y a copie de la valeur du pointeur, mais pas du contenu pointé.
Cela équivaut à un partage, et non à une copie.

Le copymemory avec des structures de types string, ne serait pas fiable en cas de modification du contenu.

La méthode de Chris est très bien, en pouvant être adaptée dans une procédure avec des pointeurs.

Code : Tout sélectionner

Structure ID 
  Nom.S 
  Prenom.S 
  Adresse.S 
EndStructure 

Procedure copy_structure_id(*adresse_1.ID,*adresse_2.ID)
  *adresse_1\Nom=*adresse_2\Nom
  *adresse_1\Prenom=*adresse_2\Prenom
  *adresse_1\Adresse=*adresse_2\Adresse
EndProcedure

Dim Perso.ID(99) 

 Perso(0)\Nom = "Dupont" 
 Perso(0)\Prenom = "Jack" 
 Perso(0)\Adresse = "3 Rue des stockosses 25000 Fleury" 

copy_structure_id(@Perso(1),@Perso(0))

Debug Perso(1)\Nom 
Debug Perso(1)\Prenom 
Debug Perso(1)\Adresse 
@ peluche
Guimauve
Messages : 1015
Inscription : mer. 11/févr./2004 0:32
Localisation : Québec, Canada

Message par Guimauve »

Je sais, j'ai eu besoin de faire un truc du genre il y a 2 ans environ. Ce n'est pas la première fois que j'en parle ici sur le forum. L'ennui c'est que le type string (.s ou $) qu'il soit une simple variable ou un champs dans une structure ne peut pas être traité comme une variable. Il faut voire ce type de variable comme étant une structure dynamique et non comme une simple variable.

On peut utiliser un CopyMemory() dans le cas d'une structure comme ceci :

Code : Tout sélectionner

Structure Matrix33

  e11.d
  e12.d
  e13.d
  e21.d
  e22.d
  e23.d
  e31.d
  e32.d
  e33.d
  
EndStructure
Et ça fonctionne très bien. Parcontre dès l'instant que l'on ajoute une champs de type .s ou $ c'est foutu. On doit obligatoirement passer par le chemin le plus long (Copie champs à champs).

Pour faire un simple Perso(0) = Perso(1) avec PureBasic c'est impossible parce qu'il est impossible de surcharger les opérateurs mathématique. Et si c'était possible, il faudrait tout de même indiquer au compilateur ce qu'il doit faire dans le cas d'un type défini par l'utlisateur. (Copie champs à champs ou CopyMemory())

A+
Guimauve
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Rebonsoir!

Merci à vous tous. Chacun y a mis sa pierre:

@Cpl, grâce à toi, j'ai compris comment fonctionne SizeOf(). T'as juste mis ID et ça m'a éclairci:

Code : Tout sélectionner

CopyMemory(Perso(0),Perso(1),SizeOf(ID))
@Guimauve, ben y a du travail sur les macros, mais, c'est plus fort que moi: ça ne me suffisait pas. Excuse-moi, je suis un flemard de première. Je préfère me prendre la tête au départ, pour glander par la suite.

@Chris, tu m'as mis la puce à l'oreille avec les +4, +8, +12, etc...

Code : Tout sélectionner

PokeS(Perso(1), PeekS(Perso(0))) 
PokeS(Perso(1)+4, PeekS(Perso(0)+4)) 
PokeS(Perso(1)+8, PeekS(Perso(0)+8))
@Lna, j'espère que tu ne m'en voudras pas, j'ai pris ta procédure, je l'ai cuisiné avec une sauce Asméarnaise. J'ai été sans pitié! Sans elle, impossible de faire sa petite soeur ci-dessous.

Esprit d'équipe tout ça :D

Je vous poste ce code (code test de Guimauve) avec la fonction ssCopy()

Syntaxe :

ssCopy(NomChaineDestination[(IndexDestination)], NomChaineSource[(IndexSource)], SizeOf(Structure) )

/!\ Ne copie que les structures contenant des chaînes de type .S.

Pour les autres types, si vous pouviez m'expliquer comment vous avez procédé, ça pourra faire une procédure plus efficace.

N'hésitez pas à me poster le rapport du moindre bug.

Code : Tout sélectionner

Procedure ssCopy(*a,*b, Size.L)
  Goto OnPasseLInutile
  UnTrucCommeCa.S = UneChoseCommeCa.S
OnPasseLInutile:
  Global PrivateValueA0.L
  For PrivateValueA0 = 0 To Size Step 4
    !  MOV    ecx, dword [v_PrivateValueA0]
    !  MOV    ebp,dword [esp+16]
    !  MOV    edx,dword [ebp+ecx]
    !  PUSH   dword [_PB_StringBasePosition]
    !  CALL  _SYS_CopyString@0
    !  MOV    ecx, dword [v_PrivateValueA0]
    !  MOV    ebp,dword [esp+16]
    !  LEA    ecx,[ebp+ecx]
    !  POP    edx
    !  CALL   SYS_AllocateString
  Next
EndProcedure 

Structure ID 
  Nom.S 
  Prenom.S 
  Adresse.S 
EndStructure 

Dim Perso.ID(99) 

Perso(0)\Nom = "Durand" 
Perso(0)\Prenom = "Jack" 
Perso(0)\Adresse = "3 Rue des stockosses 25000 Fleury" 

   ;La ligne qui couine dans la boucle For ci-dessous... 
   ;Perso(I) = Perso(0) 

For I = 1 To 5 
  ssCopy(Perso(I), Perso(0), SizeOf(ID) ) ; ...remplacée par ssCopy()
Next 

   ;...Et qui équivaudrait à ça:

; Perso(I)\Nom = Perso(0)\Nom
; Perso(I)\Prenom = Perso(0)\Prenom
; Perso(I)\Adresse = Perso(0)\Adresse

; On remplace la source pour vérifier que ce ne sont pas seulement les pointeurs qui ont été copiés...
Perso(0)\Nom = "Dupont" 
Perso(0)\Prenom = "Patrick" 
Perso(0)\Adresse = "2020 rue du fin fin" 

For Index = 0 To 5 
; ...Et on affiche le résultat  
  Debug Perso(Index)\Nom 
  Debug Perso(Index)\Prenom 
  Debug Perso(Index)\Adresse 
  Debug "" 
  
Next
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

La discussion s'est continuée sur le forum anglais.
Je vous poste ce code à titre d'exemple. Il permet de copier le champ d'une structure quelconque. Il faut néanmoins enregistrer la structure pour permettre les copies.

Code : Tout sélectionner

*ImageDeLaStructure = Struc(ChaineRepresentantLaStructure.S)
(Enregistre une structure dans une zone mémoire)

Code : Tout sélectionner

ssCopy(*ChampDest, *ChampSource)
(Cf plus haut, copie une chaîne d'un champ à l'autre. Désormais inutilisée directement)

Code : Tout sélectionner

sCopy(*ChampSource, *ChampDest, *ImageDeLaStructure)
(Dupplique complètement un champ source vers un champ destination en respectant la structure spécifiée)

Code : Tout sélectionner

Procedure Struc(Input.S) 
  Structure StringAreaStruc
    AreaStringQty.L
    AreaOffset.L
  EndStructure
  Input = UCase(Input) 
  Static Intermed.S = "" 
  Static LInput.L 
  Static Char.S{1} 
  Static Actual.S{1} 
  Static Number.S = "" 
  Static DuppMode.L 
  Static i.L 
  Static j.L 
  Static Output.S
  LInput = Len(Input) 
  For i = 1 To LInput 
    Char = Mid(Input, i, 1) 
    If Char = "]" 
      DuppMode = 0 
      Actual = Right(Intermed, 1) 
      For j = 2 To Val(Number) 
        Intermed + Actual 
      Next 
      Number = "" 
    Else 
      If Char = "["
        DuppMode = 1 
      Else 
        If DuppMode 
          Number + Char 
        Else 
          Intermed + Char 
        EndIf 
      EndIf 
    EndIf 
  Next
  Global NewList Area.StringAreaStruc()
  Static StructureSize.L
  Static IsString.L  
  Static StringQty.L
  Static StringAreaQty.L
  StringAreaQty = 0
  Input = Intermed
  LInput = Len(Input) 
  For i = 1 To LInput 
    Char = Mid(Input, i, 1)
    If Char <> "S"
      IsString = 0
    EndIf
    Select Char
      Case "B"
        StructureSize + 1
      Case "W"
        StructureSize + 2
      Case "F"
        StructureSize + 4
      Case "L"
        StructureSize + 4
      Case "D"
        StructureSize + 8
      Case "Q"
        StructureSize + 8
      Case "*"
        StructureSize + 4
      Case "S"
        If IsString = 0
          If i = LInput
            StringQty = 1
          EndIf 
          For j = i + 1 To LInput
            If Mid(Input, j, 1) <> "S"
              StringQty = j - i
              Break
            EndIf
            If j = LInput
              StringQty = (LInput - i) + 1             
            EndIf
          Next
          AddElement(Area() )
          Area()\AreaStringQty = StringQty
          Area()\AreaOffset = StructureSize
          StringAreaQty + 1
          IsString = 1
          StringQty = 0
        EndIf
        StructureSize + 4      
    EndSelect 
  Next
  *Output = AllocateMemory(8 + StringAreaQty << 3)
  *Start = *Output
  PokeL(*Start, StructureSize)
  *Start + 4
  PokeL(*Start, StringAreaQty)
  *Start + 4
  ForEach Area()
    PokeL(*Start, Area()\AreaStringQty)
    *Start + 4
    PokeL(*Start, Area()\AreaOffset)
    *Start + 4
  Next
  ClearList(Area() )
  ProcedureReturn *Output  
EndProcedure

Procedure ssCopy(*a,*b) 
Global ssCopyOffset.L 
  Goto OnPasseLInutile 
  UnTrucCommeCa.S = UneChoseCommeCa.S 
OnPasseLInutile: 
    !  MOV    ecx, dword [v_ssCopyOffset] 
    !  MOV    ebp,dword [esp+16] 
    !  MOV    edx,dword [ebp+ecx] 
    !  PUSH   dword [_PB_StringBasePosition] 
    !  CALL  _SYS_CopyString@0 
    !  MOV    ecx, dword [v_ssCopyOffset]
    !  MOV    ebp,dword [esp+16] 
    !  LEA    ecx,[ebp+ecx] 
    !  POP    edx  
    !  CALL   SYS_AllocateString 
EndProcedure 

Procedure sCopy(*Source, *Dest, *x)
  *EndArea = 0
  *Start = *x + 8
  For Area = 1 To PeekL(*x + 4)
    CopyMemory(*Source + *EndArea, *Dest + *EndArea, PeekL(*Start + 4) - *EndArea)  
    *StartString = PeekL(*Start + 4)
    For String = 0 To PeekL(*Start) - 1
      ssCopyOffset = *StartString + String << 2
      ssCopy(*Dest, *Source)
    Next
    *EndArea = PeekL(*Start + 4) + 4 * PeekL(*Start)
    *Start + 8
  Next
 CopyMemory(*Source + *EndArea, *Dest + *EndArea, PeekL(*x) - *EndArea)  
EndProcedure

; **************************************

Example:
Structure Example
  ID.L
  Age.B
  xx.B
  yy.W
  Hobby.S[3]
  Born.L
  Comment.S
  Num.L
EndStructure

Dim St.Example(3)
  *Ex = Struc("LBBWS[3]LSL")
  St(0)\ID = 321
  St(0)\Age = 29
  
  St(0)\Hobby[0] = "Foot"
  St(0)\Hobby[1] = "Hand"
  St(0)\Hobby[2] = "Basket"
  St(0)\born = 1978
  St(0)\Comment = "No more informations"
  St(0)\Num = 303030
  
  sCopy(St(0), St(1), *Ex)
  St(0)\Comment = "Other comment (modified after copy)"
  St(0)\born = 1973
  For i = 0 To 1
  Debug "St(" + Str(i) + "):"
  Debug St(i)\ID
  Debug St(i)\Age
  Debug St(i)\Hobby[0]
  Debug St(i)\Hobby[1]
  Debug St(i)\Hobby[2]
  Debug St(i)\born
  Debug St(i)\Comment
  Debug St(i)\Num
  Debug " "
  Next
Bonne programmation.
Répondre