Published on

Utiliser les opérateurs pour gérer des multitudes de conditions

 2 mins
Authors
  • avatar
    Name
    Léo Delpon
    Twitter

Supposons que vous développez un logiciel de compression de données qui peut traiter différents types de fichiers, tels que des images, des vidéos , des audios et des fichiers texte. Chaque type de fichier nécessite un algorithme de compression spécifique pour obtenir les meilleurs résultats.

Dans ce contexte, vous pourriez utiliser un mécanisme d'optimisation pour sélectionner dynamiquement l'algorithme de compression approprié en fonction du type de fichier d'entrée.

Imaginons le cas suivant avec les déclarations suivantes :


void function_false1_false2();
void function_true1_false2();
void function_false1_true2();
void function_true1_true2();

Nous avons donc quatre fonctions qui seront executées quand on rencontre les conditions qui correspondent.

Pour ce faire, il est possible de faire quelque chose comme ça en C++


// On définit un tableau qui va stocker des pointeurs de fonction
static (void)(*my_array_of_ptr_fn)(void) = { function_false1_false2, function_true1_false2, function_false1_true2, function_true1_true2 }

On a donc un tableau, si on souhaite utiliser la première fonction on ferait :

my_array_of_ptr_fn[1]();

Mais comment le faire de façon dynamique ?


// Nous allons donc utiliser les opérateurs logiques et de comparaison !
// On considère que my_condition_1 et my_condition_2 sont des booléens.
int index = my_condition_1 | my_condition_2 << 1;

Faisons un peu d'arithmétique, on sait que ici, le décalage binaire est prioritaire par rapport à l'opérateur ou.

| my_condition_1 | my_condition_2 << 1 | resultat |
|:--------------:|:-------------------:|:--------:|
| 0              | 0 << 1              | 0        |
| 1              | 0 << 1              | 1        |
| 0              | 1 << 1              | 2        |
| 1              | 1 << 1              | 3        |

Pour ceux qui ne seraient pas familier avec les opérations binaires. Je vais essayer de rappeler simplement le concept.

Dans notre cas, l'opérateur | est un OU LOGIQUE bit à bit. A ne pas confondre à || qui est simplement un opérateur OU LOGIQUE.

Exemple:


// 0 | 1 correspond sur 4 bits à ceci 
0000
0001
----
0001 

// Résultat : 1

// 2 | 1 correspond sur 4 bits à ceci

0010
0001
----
0011

// Résultat : 3

Passons maintenant au décalage binaire, je vais quand même le rappeler. Un décalage, peut soit ce faire par la gauche, soit se faire par la droite. Dans notre cas le décalage se fait par la gauche. Je vais donner quelques exemples :


// On a 1 << 1. Si on se base sur 2 bits, on a ceci 
// 01 qui sera décalé de 1 vers la gauche, on aura donc 10 en binaire sur 2 bits.
// Cela correspond à 2.
1 << 1 = 2

// Si on fait 1 >> 1, on se base sur 2 bits. On aura donc ceci 
// 01 qui sera décalé de 1 vers la droite, on aura donc 00 en binaire sur 2 bits.
// Cela correspond à 0
1 >> 1 = 0

Et voilà comment on obtient l'index du tableau correspondant !


// Voici l'exécution de la fonction par rapport à l'index
my_array_of_ptr_fn[index]();

C'est quoi l'intérêt chef ?

L'intérêt principal de cette approche réside dans la flexibilité et la réutilisation du code. Voici quelques avantages :

Sélection Conditionnelle : Vous pouvez choisir dynamiquement quelle fonction appeler en fonction de diverses conditions sans avoir besoin de plusieurs instructions if ou switch. Cela peut rendre le code plus propre et plus lisible lorsque vous avez de nombreuses conditions à gérer.

Réutilisation de Code : Si les fonctions dans my_array_of_ptr_fn effectuent des tâches similaires avec des variations mineures en fonction des conditions, vous pouvez réutiliser le même code sous forme de fonctions et les appeler en fonction des conditions, plutôt que de dupliquer du code.

Éviter la Répétition de Code : Lorsque vous avez des conditions qui se répètent dans votre code, cette approche vous permet de regrouper des fonctionnalités similaires dans des fonctions distinctes plutôt que de répéter le même code.

Facilité de Maintenance : En regroupant des fonctionnalités similaires dans des fonctions distinctes et en utilisant des pointeurs de fonctions, votre code devient plus modulaire et plus facile à maintenir. Les modifications ultérieures ne nécessitent que des modifications dans les fonctions, pas dans le code d'appel.