Pourquoi ne pas simplement stocker l'état dans un octet ? Je n'ai pas encore testé ce qui suit, mais cela devrait vous donner une idée. Vous pouvez même utiliser un short ou un int pour 16 ou 32 états. Je crois que j'ai aussi un exemple fonctionnel en JAVA. Je le posterai quand je le trouverai.
__int8 state = 0x0;
bool getState(int bit)
{
return (state & (1 << bit)) != 0x0;
}
void setAllOnline(bool online)
{
state = -online;
}
void reverseState(int bit)
{
state ^= (1 << bit);
}
Très bien, voici la version JAVA. Je l'ai stocké dans une valeur Int depuis. Si je me souviens bien, même l'utilisation d'un octet utiliserait 4 octets de toute façon. Et cela ne peut évidemment pas être utilisé comme un tableau.
public class State
{
private int STATE;
public State() {
STATE = 0x0;
}
public State(int previous) {
STATE = previous;
}
/*
* @Usage - Used along side the #setMultiple(int, boolean);
* @Returns the value of a single bit.
*/
public static int valueOf(int bit)
{
return 1 << bit;
}
/*
* @Usage - Used along side the #setMultiple(int, boolean);
* @Returns the value of an array of bits.
*/
public static int valueOf(int... bits)
{
int value = 0x0;
for (int bit : bits)
value |= (1 << bit);
return value;
}
/*
* @Returns the value currently stored or the values of all 32 bits.
*/
public int getValue()
{
return STATE;
}
/*
* @Usage - Turns all bits online or offline.
* @Return - <TRUE> if all states are online. Otherwise <FALSE>.
*/
public boolean setAll(boolean online)
{
STATE = online ? -1 : 0;
return online;
}
/*
* @Usage - sets multiple bits at once to a specific state.
* @Warning - DO NOT SET BITS TO THIS! Use setMultiple(State.valueOf(#), boolean);
* @Return - <TRUE> if states were set to online. Otherwise <FALSE>.
*/
public boolean setMultiple(int value, boolean online)
{
STATE |= value;
if (!online)
STATE ^= value;
return online;
}
/*
* @Usage - sets a single bit to a specific state.
* @Return - <TRUE> if this bit was set to online. Otherwise <FALSE>.
*/
public boolean set(int bit, boolean online)
{
STATE |= (1 << bit);
if(!online)
STATE ^= (1 << bit);
return online;
}
/*
* @return = the new current state of this bit.
* @Usage = Good for situations that are reversed.
*/
public boolean reverse(int bit)
{
return (STATE ^= (1 << bit)) == (1 << bit);
}
/*
* @return = <TRUE> if this bit is online. Otherwise <FALSE>.
*/
public boolean online(int bit)
{
int value = 1 << bit;
return (STATE & value) == value;
}
/*
* @return = a String contains full debug information.
*/
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
sb.append("TOTAL VALUE: ");
sb.append(STATE);
for (int i = 0; i < 0x20; i++)
{
sb.append("\nState(");
sb.append(i);
sb.append("): ");
sb.append(online(i));
sb.append(", ValueOf: ");
sb.append(State.valueOf(i));
}
return sb.toString();
}
}
Je dois également souligner que vous ne devriez pas vraiment utiliser une classe spéciale pour cela, mais simplement avoir la variable stockée dans la classe qui sera la plus susceptible de l'utiliser. Si vous prévoyez d'avoir des centaines ou même des milliers de valeurs booléennes, pensez à un tableau d'octets.
Par exemple, l'exemple ci-dessous.
boolean[] states = new boolean[4096];
peut être convertie en la formule ci-dessous.
int[] states = new int[128];
Maintenant, vous vous demandez probablement comment accéder à l'index 4095 à partir d'un tableau de 128. Donc ce que cela fait, c'est que si nous le simplifions. Le 4095 est décalé de 5 bits vers la droite, ce qui est techniquement la même chose que de diviser par 32. Donc 4095 / 32 = arrondi vers le bas (127). Nous sommes donc à l'index 127 du tableau. Ensuite, nous exécutons 4095 & 31, ce qui lui donnera une valeur comprise entre 0 et 31. Cela ne fonctionnera qu'avec les puissances de deux moins 1. Par exemple, 0,1,3,7,15,31,63,127,255,511,1023, etc...
Donc maintenant nous pouvons accéder au bit à cette position. Comme vous pouvez le voir, c'est très très compact et c'est mieux que d'avoir 4096 booléens dans un fichier :) Cela permettra également une lecture/écriture beaucoup plus rapide d'un fichier binaire. Je n'ai aucune idée de ce qu'est ce truc de BitSet, mais ça ressemble à un déchet complet et puisque byte, short, int, long sont déjà sous leurs formes binaires, techniquement, vous pourriez aussi bien les utiliser tels quels. Ensuite, il faut créer une classe complexe pour accéder aux bits individuels de la mémoire, c'est ce que j'ai pu comprendre en lisant quelques messages.
boolean getState(int index)
{
return (states[index >> 5] & 1 << (index & 0x1F)) != 0x0;
}
Plus d'informations...
Si ce qui précède est un peu confus, voici une version simplifiée de ce qui se passe.
Les types " octet ", " court ", " int ", " long "sont tous des types de données qui ont des plages différentes.
Vous pouvez consulter ce lien : http://msdn.microsoft.com/en-us/library/s3f49ktz(v=vs.80).aspx
Pour voir les plages de données de chacun.
Un octet est donc égal à 8 bits. Ainsi, un int qui est de 4 octets sera de 32 bits.
Maintenant, il n'y a pas de moyen facile d'apporter une valeur à l'élément N puissance. Cependant, grâce au décalage des bits, nous pouvons le simuler quelque peu. En effectuant 1 << N cela équivaut à 1 * 2^N. Donc si nous faisions 2 << 2^N, nous ferions 2 * 2^N. Donc pour effectuer des puissances de deux, il faut toujours faire "1 << N".
Nous savons maintenant qu'un int aura 32 bits et que nous pouvons utiliser chaque bit pour simplement les indexer.
Pour simplifier les choses, considérez l'opérateur "&" comme un moyen de vérifier si une valeur contient les bits d'une autre valeur. Disons que nous avons une valeur de 31. Pour arriver à 31, nous devons ajouter les bits suivants de 0 à 4. Qui sont 1,2,4,8, et 16. La somme de tous ces bits est égale à 31. Maintenant, lorsque nous exécutons 31 & 16, cela renvoie 16 parce que le bit 4, qui est 2^4 = 16. est situé dans cette valeur. Maintenant, disons que nous avons exécuté 31 & 20 qui vérifie si les bits 2 et 4 sont situés dans cette valeur. Cela retournera 20 puisque les deux bits 2 et 4 sont situés ici 2^2 = 4 + 2^4 = 16 = 20. Maintenant disons que nous avons fait 31 & 48. Cela vérifie les bits 4 et 5. Eh bien, nous n'avons pas le bit 5 dans 31. Donc cela ne retournera que 16. Il ne retournera pas 0. Ainsi, lorsque vous effectuez des contrôles multiples, vous devez vérifier que la valeur est physiquement égale à cette valeur. Au lieu de vérifier si elle est égale à 0.
Le programme ci-dessous vérifie si un bit individuel est à 0 ou à 1. 0 étant faux, et 1 étant vrai.
bool getState(int bit)
{
return (state & (1 << bit)) != 0x0;
}
L'exemple ci-dessous permet de vérifier si deux valeurs contiennent ces bits. Pensez-y comme si chaque bit était représenté par 2^BIT, donc lorsque nous faisons
Je vais passer rapidement en revue certains des opérateurs. Nous venons d'expliquer légèrement l'opérateur "&". Maintenant, l'opérateur "|".
Lorsque vous effectuez les opérations suivantes
int value = 31;
value |= 16;
value |= 16;
value |= 16;
value |= 16;
La valeur sera toujours de 31. C'est parce que le bit 4 ou 2^4=16 est déjà activé ou mis à 1. Donc l'exécution de "|" retourne cette valeur avec ce bit activé. S'il est déjà activé, aucun changement n'est effectué. Nous utilisons "|=" pour donner à la variable la valeur retournée.
Au lieu de faire -> "valeur = valeur | 16 ;". On fait juste "valeur |= 16 ;".
Voyons maintenant un peu plus en détail comment le " & " et " | " peut être utilisé.
/*
* This contains bits 0,1,2,3,4,8,9 turned on.
*/
const int CHECK = 1 | 2 | 4 | 8 | 16 | 256 | 512;
/*
* This is some value were we add bits 0 through 9, but we skip 0 and 8.
*/
int value = 2 | 4 | 8 | 16 | 32 | 64 | 128 | 512;
Ainsi, lorsque nous exécutons le code ci-dessous.
int return_code = value & CHECK;
Le code de retour sera 2 + 4 + 8 + 16 + 512 = 542.
Donc, nous vérifiions 799, mais nous avons reçu 542. C'est parce que les bits o et 8 sont hors ligne ; ils sont égaux à 256 + 1 = 257 et 799 - 257 = 542.
Ce qui précède est un excellent moyen de vérifier si, par exemple, nous créons un jeu vidéo et que nous voulons vérifier si tel ou tel bouton a été enfoncé, si l'un d'entre eux l'a été. Nous pourrions simplement vérifier chacun de ces bits avec une seule vérification et ce serait beaucoup plus efficace que d'effectuer une vérification booléenne sur chaque état.
Disons maintenant que nous avons une valeur booléenne qui est toujours inversée.
Normalement, vous devriez faire quelque chose comme
bool state = false;
state = !state;
Il est possible de le faire avec des bits en utilisant le " ^ " opérateur.
Tout comme nous avons effectué "1 << N" pour choisir la valeur entière de ce bit. Nous pouvons faire la même chose avec l'inverse. Donc, tout comme nous avons montré comment "|=" stocke le retour, nous allons faire la même chose avec "^=". Donc ce que cela fait, c'est que si ce bit est activé, nous le désactivons. S'il est désactivé, nous l'activons.
void reverseState(int bit)
{
state ^= (1 << bit);
}
Vous pouvez même lui faire renvoyer l'état actuel. Si vous voulez qu'il renvoie l'état précédent, il suffit de remplacer "!=" par "==". Donc, cette fonction effectue l'inversion puis vérifie l'état actuel.
bool reverseAndGet(int bit)
{
return ((state ^= (1 << bit)) & (1 << bit)) != 0x0;
}
Il est également possible de stocker plusieurs valeurs non monobit (bool) dans un int. Disons que nous écrivons normalement notre position de coordonnées comme ci-dessous.
int posX = 0;
int posY = 0;
int posZ = 0;
Maintenant, disons que ceux-ci ne sont jamais passés 1023. Donc, de 0 à 1023, c'était la distance maximale pour tous ces cas. Je choisis 1023 pour d'autres raisons, comme mentionné précédemment, vous pouvez manipuler la variable "&" comme un moyen de forcer une valeur entre 0 et 2^N - 1 valeurs. Donc disons que votre plage est de 0 à 1023. Nous pouvons exécuter "valeur & 1023" et ce sera toujours une valeur entre 0 et 1023 sans aucune vérification des paramètres d'index. Gardez à l'esprit que, comme mentionné précédemment, cela ne fonctionne qu'avec les puissances de deux moins un. 2^10 = 1024 - 1 = 1023.
Par exemple, plus de if (valeur >= 0 && valeur <= 1023).
Donc 2^10 = 1024, ce qui nécessite 10 bits pour contenir un nombre entre 0 et 1023.
Donc 10x3 = 30, ce qui est toujours inférieur ou égal à 32. est suffisant pour contenir toutes ces valeurs dans un int.
Nous pouvons donc effectuer ce qui suit. Donc pour voir combien de bits nous avons utilisé. On fait 0 + 10 + 20. La raison pour laquelle j'ai mis le 0 ici est pour vous montrer visuellement que 2^0 = 1 donc # * 1 = #. La raison pour laquelle nous avons besoin de y << 10 est que x utilise 10 bits qui vont de 0 à 1023. Nous devons donc multiplier y par 1024 pour avoir des valeurs uniques pour chacun. Ensuite, Z doit être multiplié par 2^20, ce qui fait 1 048 576.
int position = (x << 0) | (y << 10) | (z << 20);
Les comparaisons sont ainsi rapides.
Nous pouvons maintenant faire
return this.position == position;
par rapport à
return this.x == x && this.y == y && this.z == z;
Et si nous voulions les positions réelles de chacun ?
Pour le x, nous faisons simplement ce qui suit.
int getX()
{
return position & 1023;
}
Ensuite, pour le y, nous devons effectuer un décalage de bit à gauche puis un ET.
int getY()
{
return (position >> 10) & 1023;
}
Comme vous pouvez le deviner, le Z est le même que le Y, mais au lieu de 10, nous utilisons 20.
int getZ()
{
return (position >> 20) & 1023;
}
J'espère que les personnes qui liront ce document y trouveront des informations utiles :).