Aller au contenu


Photo
- - - - -

Comment avoir l'équivalent des unions C++ ou des arrayBuffer javascrypt en Java?

union structure classe java

  • Veuillez vous connecter pour répondre
6 réponses à ce sujet

#1 Mike118

Mike118

    Staff Robot Maker

  • Administrateur
  • PipPipPipPipPip
  • 9 969 messages
  • Gender:Male
  • Location:Anglet

Posté 17 avril 2022 - 07:40

J'aimerais faire l'équivalent de ce qu'on peut faire avec des unions en c++ mais en java
Cependant mon java est visiblement plus que rouillé et je ne trouve pas la meilleur façon de faire un équivalent en java de ce genre de chose : 
 

typedef struct {
 union {
  struct {
   int16_t x;
   int16_t y;
  };
  int16_t coordonnees[2];
  uint8_t bytes[4];
 };
} Point;

Grâce à l'union si je fais 

Point monPoint = { 0,0}; 
je peux aussi faire des truc du genre 
monPoint.x = 1;  // change le 0 en 1
monPoint.coordonnees[0] = 2; // change le monPoint.x =1 en 2 ...

Exemple de ma classe équivalent en java  

 

class Point {
  public short x;   // 2 octets
  public short y;   // 2 octets 
  public Point(int x, int y) {
    this.x = (short)x;
    this.y = (short)y;
  }
}
 

J'aimerais trouver le moyen de la modifier ajouter des "vues" en  "bytes"  et "coordonnées " pour pouvoir faire des truc du genre : 

Point monPoint = new Point(0,0);
monPoint.coords[0]=1;  // change monPoint.x de 0 à 1 équivaut à  monPoint.x =1 et on peut aussi lire monPoint.bytes[0] = 0 et monPoint.bytes[1] = 1 ...

le but étant de pouvoir indépendamment remplir et lire aussi bien en bytes en coordonnées ou bien en x et en y ...

L'idéal étant de pouvoir directement me reposer sur la structure mémoire comme je le fais avec les union en C de manière à ne pas avoir à utiliser des méthodes spécifique à chaque fois et ou à dédoubler les variables ...

Bref quelqu'un aurait il quelque chose de plus élégant à proposer que ça  : 

 

class Point {
  public short x;
  public short y;
  public short [] coords = new short[2];
  public byte [] bytes = new byte[4];
  public Point(int x, int y) {
   updateFromXY( x, y);
  }
  
  public Point(byte xl, byte xh, byte yl, byte yh) {
    this.updateFromBytes(xl, xh, yl, yh);
  }
  
  public void coords(int n, int val) {
    this.coords[n]=(short)val;
    updateFromXY(this.coords[0] , this.coords[1]);
  }
  
  public void x(int val) {
    this.x=(short)val;
    updateFromXY(this.x , this.y);
  }
  
  public void y(int val) {
    this.y=(short)val;
    updateFromXY(this.x , this.y);
  }
  
  public void bytes(int n, int val) {
    this.bytes[n]=(byte)val;
    updateFromBytes(this.bytes[0], this.bytes[1], this.bytes[2], this.bytes[3]);
  }
  
  private void updateFromXY(int x, int y) {
    this.x = (short)x;
    this.y = (short)y;
    this.coords[0] = this.x;
    this.coords[1] = this.y;
    this.bytes[0] = (byte)(x & 255);
    this.bytes[1] = (byte)(x >> 8);
    this.bytes[2] = (byte)(y & 255);
    this.bytes[3] = (byte)(y >> 8);
  }
  
  private void updateFromBytes(byte xl, byte xh, byte yl, byte yh) {
    this.bytes[0] = xl;
    this.bytes[1] = xh;
    this.bytes[2] = yl;
    this.bytes[3] = yh;
    int x =  xh << 8 + xl;
    int y = yh << 8 + yl;
    this.x = (short)x;
    this.y = (short)y;
    this.coords[0] = this.x;
    this.coords[1] = this.y;
  }
}

car dans l'exemple ci dessus, je "triple l'usage mémoire" et pour " écrire les valeurs je dois passer par des méthodes qui mettent à jour les autres variables ... 

à l'usage ça me donne un truc du genre : 
 

Point monPoint = new Point(0,0);
monPoint.coords(0,1); // Met la coordonnées 0 = x à 1 
/*
monPoint.coords[0]    ( pour lire la valeur de x la coordonnée 0 qui vaut 1 ... )
monPoint.byte[1]   ( pour lire l'octet de poids faible de x et qui vaut 1 ,
*/
monPoint.x(2);  // Met x à 2 

Grosso modo avec cette solution bien que je ne trouve pas ça super élégante, mon cahier des charges est bien respecté en terme d'usage... Mais je me demande quand même si il y a pas moyen de faire " plus élégants sans la redondance mémoire " et l'usage de code "d'update " , "plus automatique " ... et donc aussi plus " rapide à exécuter "...

En javascrypt pour faire ce genre de chose j'ai utilisé des arrayBuffer ...

class Point {
 constructor(x,y) {
  this.arrayBuffer = new ArrayBuffer(4);
  this.x = new Int16Array(this.arrayBuffer, 0, 1);
  this.y = new Int16Array(this.arrayBuffer, 1, 1);
  this.coords = new Int16Array(this.arrayBuffer, 0, 2);
  this.bytes = new Uint8Array(this.arrayBuffer);
  this.coords[0]=x;   // équivaut à faire this.x[0] = x; 
  this.coords[1]=y;   //  et this.y[0] = y; 
 }
}



  à l'écriture de la classe c'est "un petit peu lourd "  car on utilise des tableaux même quand on a un seul élément et donc à chaque fois il faut spécifier le [0] dans ce cas notamment avec .x[0] et .y[0]  ... mais mis à part ce point de détails, les performances et les fonctionnalités sont bien là, sans redondance mémoire, ni fonction d'update ... Y a t il un équivalent des arrayBuffer et de leur " vue typé"  en java ?


Si mon commentaire vous a plus laissez nous un avis  !  :thank_you:

Nouveau sur Robot Maker ? 

Jetez un oeil aux blogs, aux tutoriels, aux ouvrages, au robotscope  aux articles,  à la boutique  et aux différents services disponible !
En attendant qu'une bibliothèque de fichiers 3D soit mise en place n'hésitez pas à demander si vous avez besoin du fichier 3D d'un des produits de la boutique... On l'a peut être ! 
Si vous souhaitez un robot pilotable par internet n'hésitez pas à visiter www.vigibot.com et à lire le sous forum dédié à vigibot!

 

Les réalisations de Mike118  

 

 

 


#2 zavatha

zavatha

    Habitué

  • Membres
  • PipPip
  • 233 messages
  • Gender:Male

Posté 17 avril 2022 - 01:06

Salut,

 

Pas sûr d'avoir compris ce que tu veux faire... et je précise que la dernière fois que j'ai fait du java ct il y a 4ans environ pour porter une petite appli initialement développée en .net

donc c'est loin !

 

bref, ce que j'ai pas capté : tu as l'air de systématiquement faire une affectation de x et y, puis un report de de ces valeurs dans coords (x = 1; y = 2; coords[0] = 1; coords[1] = 2;)

 

dans ce cas, tu alloues 2 fois ta mémoire (en int16). si c'est une volontée (copies indépendantes des valeurs, ne touches à rien ^^).

sinon (ie tu veux toujours des valeurs identiques), tu peux peut être initialiser ton coords avec les adresses mémoire de tes 2 variables avec un truc du genre : 

 

int16 x = 0;

int16 y = 0;

int16*[] coords[2];

coords[0] = &x;

coords [1]= &y;

 

comme cela, coords est un tableau de pointeurs sur les tes coordonnées x et y. il est initialisé une fois pour toutes à la création de ton "objet" (qui n'en est pas un dans ton cas)...

 

maintenant : 1/ mon java est loin, mes pointeurs aussi et j'ai même pas sun environement OP pour tester ce que je dis => je sais même pas si ça compile ni si cette syntaxe est correcte en java ^^

2/ est-je bien compris l'énoncé ? :P

 

@+

 

Zav !



#3 Mike118

Mike118

    Staff Robot Maker

  • Administrateur
  • PipPipPipPipPip
  • 9 969 messages
  • Gender:Male
  • Location:Anglet

Posté 17 avril 2022 - 03:47

Salut,

 

Pas sûr d'avoir compris ce que tu veux faire... et je précise que la dernière fois que j'ai fait du java ct il y a 4ans environ pour porter une petite appli initialement développée en .net

donc c'est loin !

 

bref, ce que j'ai pas capté : tu as l'air de systématiquement faire une affectation de x et y, puis un report de de ces valeurs dans coords (x = 1; y = 2; coords[0] = 1; coords[1] = 2;)

 

dans ce cas, tu alloues 2 fois ta mémoire (en int16). si c'est une volontée (copies indépendantes des valeurs, ne touches à rien ^^).

sinon (ie tu veux toujours des valeurs identiques), tu peux peut être initialiser ton coords avec les adresses mémoire de tes 2 variables avec un truc du genre : 

 

int16 x = 0;

int16 y = 0;

int16*[] coords[2];

coords[0] = &x;

coords [1]= &y;

 

comme cela, coords est un tableau de pointeurs sur les tes coordonnées x et y. il est initialisé une fois pour toutes à la création de ton "objet" (qui n'en est pas un dans ton cas)...

 

maintenant : 1/ mon java est loin, mes pointeurs aussi et j'ai même pas sun environement OP pour tester ce que je dis => je sais même pas si ça compile ni si cette syntaxe est correcte en java ^^

2/ est-je bien compris l'énoncé ? :P

 

@+

 

Zav !

 

justement tu as bien compris ce que je veux faire et justement la solution que j'ai a l'inconvénient de doubler ( et même tripler dans ce cas précis ) l'allocation mémoire. Ce qui est justement le point que je critique... 
Et donc dans l'idée oui je cherche bien à faire un truc du genre de ce que tu proposes ... 
Mais en effet ta syntaxe n'est pas correcte ... 

Si tu veux facilement un environnement pour tester ta syntaxe tu peux éventuellement installer processing  https://processing.org/download/ 
Ma question est en lien avec :  https://www.robot-ma...ous-processing/( je vais bientôt proposer une seconde version avec la communication avec l'arduino et je cherche ça pour faire un protocole de communication sympas:)  / plus optimisée en envoyant les données ( pour enoyer la donnée 123, on peut le faire en un octet plutôt que en que d'envoyer 3 octets pour envoyer '1' '2' '3' ...)


Si mon commentaire vous a plus laissez nous un avis  !  :thank_you:

Nouveau sur Robot Maker ? 

Jetez un oeil aux blogs, aux tutoriels, aux ouvrages, au robotscope  aux articles,  à la boutique  et aux différents services disponible !
En attendant qu'une bibliothèque de fichiers 3D soit mise en place n'hésitez pas à demander si vous avez besoin du fichier 3D d'un des produits de la boutique... On l'a peut être ! 
Si vous souhaitez un robot pilotable par internet n'hésitez pas à visiter www.vigibot.com et à lire le sous forum dédié à vigibot!

 

Les réalisations de Mike118  

 

 

 


#4 zavatha

zavatha

    Habitué

  • Membres
  • PipPip
  • 233 messages
  • Gender:Male

Posté 19 avril 2022 - 09:11

Salut Mike,

 

Je me suis renseigné un peu hier sur le Java, mais n'ai pas eu le temps de poster ma réponse avant...

c pas foufou...

à priori pas de GET / SET comme en .net

si j'ai bien compris, pas de référence sur les types primitifs (ça reste à vérifier, j'ai lu en diagonale) non plus...

 

J'ai pondu ça : 

// Classe Point
class Point {
  private Integer [] Coords = {x, y};

  // setter X
  public void SetX(Integer xx) {
    Coords[0] = xx;
  }
  // egtter X
  public Integer GetX() {
    return Coords[0];
  }

  // setter Y
  public void SetY(Integer yy) {
    Coords[1] = yy;
  }

  // getter Y
  public Integer GetY() {
    return Coords[1];
  }

  public Point(int xx, int yy) {
    this.Coords[0] = xx;
    this.Coords[1] = yy;
  }

  public Integer[] GetCoords() {
    //return new Integer[]{Coords[0], Coords[1]};
    return Coords;
  }
} // fin de classe Point

Je me suis appuyé sur le type Integer qui à priori encapsule le type primitif int dans un objet...

L'intérêt est de pouvoir ainsi utiliser les références de tes valeurs (c'est un objet, donc accédé par sa référence) => on peut mettre ça dans un tableau de Integer[]... sans avoir à maintenir à côté les variables x et y en paralèlle qui disparaissent...

puis travailler sur le tableau directement pour les GETs et SETs...

 

Comme tu vois, je n'ai pas développé tout ce que tu attends faute de temps....j 'ai repris le boulot aujourd'hui... dommage que je n'ai pas eu le temps de me connecter au forum au début de mes congés, je trouvait la question intéressante :) ...

 

Pas de get/set => utilisation obligatoire de méthodes pour faire les affectations et lectures de valeurs dans le tableau... (C# c'est bien en fait :P)

 

on s'éloigne donc de ta demande initiale (le struct) pour se rapprocher de ta solution (la classe point). avec peut être une petite économie d'allocation mémoire... mais est-ce vraiment substantiel / intéressant au vu de de la petite taille de l'appli ?

je ne me suis pas mouillé à traiter la question des bytes non plus ^^

vas savoir, si ça se trouve mon truc ne remplit pas le contrat...

en plus je crois me souvenir que je type Integer est deprecated depuis Java 8 (?)... à vérifier également...

 

je ne sais pas si il y a des équivalents à Integer pour d'autres types ? (tuj risques d'avoir besoin de float / long / decimal ou autre chose que des entiers non ?

 

Une piste à tout hasard (c'est par là que mon esprit tordu m'oriente tout de suiste là, sans avoir ni cherché ni réfléchit : 

N'y aurait il pas moyen de te compiler une dll faite en C à référencer ensuite dans Processing ?

En effet, quand j'étais stagiaire (bon OK ça remonte à Java2 ^^), une collègue à moi avait fait ça : compilation d'un ensemble de dlls écrites en c (un moteur de calculs), et intégration dans une UI développée en Java...

Peut être que processing le permet-il ?

 

Pour info, avec ma classe, la ligne suivante saisie dans la méthode KeyPressed() renvoie 3 couples de valeurs identiques : 

println("Position : [" +  position.GetX() + "," + position.GetY() + "]" + " / infos : [" + position.GetCoords()[0] + "," + position.GetCoords()[1] + "]" + "ref : [" + x + "," + y + "]");

 

tiens moi au jus... si je ne suis aps encore le sujet je vais le faire... ;)

 

++

Zav



#5 Mike118

Mike118

    Staff Robot Maker

  • Administrateur
  • PipPipPipPipPip
  • 9 969 messages
  • Gender:Male
  • Location:Anglet

Posté 19 avril 2022 - 11:10

Du coup au vu de ta réponse et au lieu de " dédoubler la mémoire "  j'en viens à proposer ça très proche de ce que j'avais avant mais sans dédoubler la mémoire: 

 

class Point {
  private short coords[] = new short[2];
  
  public Point(int x, int y) {
   this.coords[0] = (short)x;
   this.coords[1] = (short)y;
  }
  
  public Point(byte xl, byte xh, byte yl, byte yh) {
    this.coords[0] = (short) ( xh << 8 + xl);
    this.coords[1] = (short) ( yh << 8 + yl);
  }
  
  public short coords(int n) {
    return this.coords[n];
  }
  
  public short x() {
    return this.coords[0];
  }
  
  public short y() {
    return this.coords[1];
  }
  
  public void coords(int n, int val) {
    this.coords[n]=(short)val;
  }
  
  public void x(int val) {
    this.coords[0]=(short)val;
  }
  
  public void y(int val) {
    this.coords[1]=(short)val;
  }
  
  public byte bytes(int n) {
   int sum = this.coords[1] << 16 + this.coords[0];
   return (byte)((sum >> (n * 8)) & 255);
  }
  
  public void bytes(int n, int val) {
    byte [] bytes = new byte[4];
    bytes[0] = (byte)(this.coords[0] & 255);
    bytes[1] = (byte)(this.coords[0] >> 8);
    bytes[2] = (byte)(this.coords[1] & 255);
    bytes[3] = (byte)(this.coords[1] >> 8);
    bytes[n] = (byte) val;
    this.coords[0]=(short)(bytes[1] << 8 + bytes[0]);
    this.coords[1]=(short)(bytes[3] << 8 + bytes[2]);
  }
} 

ça marche ... Du coup au lieu de pouvoir récupérer directement les valeurs comme ce que je faisais au départ avec des propriétés "public" il faut dans ce cas absolument passer par les getters et setters ... ( j'ai pas mis les mots clefs get et set à chaque fois, je me base sur le polymorphisme pour que la classe gère d'elle même la différence entre le get :  point.x() et le set :  point.x(val) ... afin d'avoir des noms plus "court" et proche de ce que j'utilise avec mes structures ... 

Du coup le gros inconvénient c'est de devoir écrire chaque get et set souhaité dans la classe... là ou précédemment je n'avais que à rédiger les sets ... mais qui au final se retrouve plus léger que la précédente classe ...

Pour un truc comme juste le point ça va ... Mais pour une grosse structure comme celle utilisée sur vigibot et qui est en plus en taille dynamique c'est un peu plus relou à faire x) 

Après bon, en théorie c'est un truc qu'on rédige une bonne fois pour toute et après c'est bon ^^ .

N'empêche les structure les unions et les pointeurs ça a du bon quand même, parfois ça manque quand tu ne les as pas x)


Si mon commentaire vous a plus laissez nous un avis  !  :thank_you:

Nouveau sur Robot Maker ? 

Jetez un oeil aux blogs, aux tutoriels, aux ouvrages, au robotscope  aux articles,  à la boutique  et aux différents services disponible !
En attendant qu'une bibliothèque de fichiers 3D soit mise en place n'hésitez pas à demander si vous avez besoin du fichier 3D d'un des produits de la boutique... On l'a peut être ! 
Si vous souhaitez un robot pilotable par internet n'hésitez pas à visiter www.vigibot.com et à lire le sous forum dédié à vigibot!

 

Les réalisations de Mike118  

 

 

 


#6 Sandro

Sandro

    Pilier du forum

  • Modérateur
  • PipPipPipPipPip
  • 1 262 messages
  • Gender:Male

Posté 20 avril 2022 - 07:44

Pour faire court, il me semble (ça fait quelques années que j'ai plus fait de java) que Java est tout simplement un langage "haut niveau", qui ne permet pas un accès bas niveau comme tu le souhaiterais.

En effet, si autorises les unions, tu peux facilement rompre les invariants de tes types. Par exemple, si tu as un "pointeur" (une référence) dans ton code, tu risque de l'écraser "discrètement", et de perdre accès à l'objet, sans que le garbage collector soit au courant. Ou si tu as un objet directement dans l'union, tu peux modifier ses champs privés et rompre ses invariants. Même un type aussi basic qu'un double n'est pas sur dans une union : il y a une famille de valeurs spéciales (NaN, +inf, -inf, ...) que tu peux générer, ou pire encore, il y a des valeurs qui ne correspondent à rien (ie qui sont de la même "famille" que NaN et inf, mais sans que le code correspondant soit utilisé).

 

Après, est-ce que tu te soucie vraiment d'avoir quelques octets en plus ou de ralentir un tout petit peu les accès? Si oui, alors probablement Java n'est pas le meilleurs langage de toute façon, vu que ce n'est compilé qu'à moitié.

 

Après, si vraiment tu veux faire des accès plus directs, regarde la classe Unsafe, ça pourrait peut-être être une piste (j'ai pas assez creusé pour être sur)


Aidez-nous à vous aider : partagez toutes les informations pertinentes : description précise du problème, contexte, schéma de câblage, liens vers la documentation des composants, votre code (ou encore mieux un code minimal reproduisant le bug), ...

Vous recevrez ainsi plus de réponses, et elles seront plus pertinentes.


#7 Mike118

Mike118

    Staff Robot Maker

  • Administrateur
  • PipPipPipPipPip
  • 9 969 messages
  • Gender:Male
  • Location:Anglet

Posté 20 avril 2022 - 09:49

Pour faire court, il me semble (ça fait quelques années que j'ai plus fait de java) que Java est tout simplement un langage "haut niveau", qui ne permet pas un accès bas niveau comme tu le souhaiterais.

En effet, si autorises les unions, tu peux facilement rompre les invariants de tes types. Par exemple, si tu as un "pointeur" (une référence) dans ton code, tu risque de l'écraser "discrètement", et de perdre accès à l'objet, sans que le garbage collector soit au courant. Ou si tu as un objet directement dans l'union, tu peux modifier ses champs privés et rompre ses invariants. Même un type aussi basic qu'un double n'est pas sur dans une union : il y a une famille de valeurs spéciales (NaN, +inf, -inf, ...) que tu peux générer, ou pire encore, il y a des valeurs qui ne correspondent à rien (ie qui sont de la même "famille" que NaN et inf, mais sans que le code correspondant soit utilisé).

 

Après, est-ce que tu te soucie vraiment d'avoir quelques octets en plus ou de ralentir un tout petit peu les accès? Si oui, alors probablement Java n'est pas le meilleurs langage de toute façon, vu que ce n'est compilé qu'à moitié.

 

Après, si vraiment tu veux faire des accès plus directs, regarde la classe Unsafe, ça pourrait peut-être être une piste (j'ai pas assez creusé pour être sur)

 

C'est pas que je cherchais absolument à faire des accès plus direct, c'est juste que je cherchais la façon la plus efficace de le faire pour pouvoir envoyer de manière optimisée les données dans un port série octet par octet et non pas sous forme de chaîne de caractère
Dans l'idée je cherchais surtout ce qu'il y avait de "plus naturel" pour essayer si possible d'éviter de devoir faire les méthodes à la mano :) 


Exemple de structure plus " complexe " : 

 

typedef struct {
 union {
  struct {
   int16_t x;
   int16_t y;
  };
  int16_t coordonnees[2];
  uint8_t bytes[4];
 };
} Point;

typedef struct {
 union {
  struct {
   int8_t x;
   int8_t y;
   int8_t z;
  };
  uint8_t bytes[3];
 };
} Vitesses;


// CONFIG 

#define NBPOSITIONS 2
#define TXFRAMESIZE (NBPOSITIONS * 4 + 17)

typedef struct {
 union {
  struct {
   uint8_t sync[4];               // 4
   Point positions[NBPOSITIONS];  // NBPOSITIONS * 4
   uint16_t val16[2];             // 2 * 2
   uint8_t choixCameras;          // 1
   Vitesses vitesses;             // 3
   uint8_t interrupteurs;         // 1
   uint8_t val8[4];               // 4
  };

  uint8_t bytes[TXFRAMESIZE];
 };
} TrameTx;

Mon instinct me dit qu'il doit y avoir un truc tout fait et que je ne devrais pas avoir à réinventer la roue... Et après un petit peu plus de recherche je pense que je dois creuser de ce côté : 
https://www.javatpoint.com/serialization-in-java 

qui il me semble est censé faire exactement ce dont j'ai besoin ...

Il me reste à savoir comment utiliser cette classe avec le port série ... à faire un code d'exemple et tester pour voir comment ça marche ... 


 


Si mon commentaire vous a plus laissez nous un avis  !  :thank_you:

Nouveau sur Robot Maker ? 

Jetez un oeil aux blogs, aux tutoriels, aux ouvrages, au robotscope  aux articles,  à la boutique  et aux différents services disponible !
En attendant qu'une bibliothèque de fichiers 3D soit mise en place n'hésitez pas à demander si vous avez besoin du fichier 3D d'un des produits de la boutique... On l'a peut être ! 
Si vous souhaitez un robot pilotable par internet n'hésitez pas à visiter www.vigibot.com et à lire le sous forum dédié à vigibot!

 

Les réalisations de Mike118  

 

 

 






Aussi étiqueté avec au moins un de ces mots-clés : union, structure, classe, java

0 utilisateur(s) li(sen)t ce sujet

0 members, 0 guests, 0 anonymous users