mardi 22 décembre 2015

Utiliser ERB en c++, ou comment transformer un language sexy comme ruby en quelque-chose qui fait peur !

On a beau dire, le c et le c++ sont quand même les langages les plus puissant qui existent (surtout c++ en fait), mais il sont complexes et surtout ne sont pas interprétés !

Pour pallier certain manques de ces langages il est possible de rendre scriptable une application, via une api vers un langage interprété.

Ici on s’intéresse au problème suivant: on veut permettre à l'utilisateur d'inclure certaines commande pour rendre dynamique un document texte qu'il éditerai depuis une application écrite en c++.

J'ai cherché diverses solutions et c'est finalement Ruby qui a retenus mon attention, notamment à cause d'erb, le langage de template intégré à Ruby.

Prenons un exemple simple, un petit code ruby utilisant erb pour imprimer un petit hello world:


#!/usr/bin/ruby

require 'erb'

my_template = "Hello World\nToday is <%# this is just a comment %> <%= MyModule.MyFunc()%>\n"

module MyModule
          def self.MyFunc()
                    Time.now.strftime('%A')
          end
end

my_erb = ERB.new(my_template)
puts my_erb.result()


Mais maintenant, addmettons que l'on veuille faire la même chose en c++, cad au moins pouvoir créer une fonction qui puisse employer les données de nos variables c++ pour les employer dans ruby.

Pour ce faire on va passer par l'API c de ruby, pour ceux qui ne connaissent pas un petit lien sur le tuto !


Le premier défis consiste à obtenir les fichiers de développement ruby, sous ubuntu 15.04 il suffit d'installer ruby-all-dev:

sudo apt-get install ruby-all-dev

Si comme moi vous souhaitez aussi employer pkg-config il faut installer aussi ruby-pkg-config

sudo apt-get install ruby-pkg-config

Voilà, nous sommes prêts à utiliser ruby à l'intérieur de c ou c++. Donc, ça donne quoi le script d'en dessus en c++ ?


#include <iostream>
#include <ruby.h>

#include <cstdio>
#include <ctime>


using namespace
std;

const string erb_line = "Hello World\nToday is <%# this is just a comment %><%= MyModule.MyFunc()%>\n";

VALUE MyFunc(int argc, VALUE* argv, VALUE self) {
  
    time_t rawtime;
    tm* timeinfo;
    char buffer [80];

    time(&rawtime);
    timeinfo = localtime(&rawtime);

    strftime(buffer,80,"%A",timeinfo);
  
    string timeString(buffer);
  
    return rb_str_new2(timeString.c_str());
  
}

int main(int argc, char ** argv){
  
    /* construct the VM */
    ruby_init();
  
    /* Ruby goes here */
    ruby_init_loadpath();
    rb_require("erb");
  
    // Define a new module    
    VALUE mymodule = rb_define_module("MyModule");
    //add a function to the module
    rb_define_module_function(mymodule, "MyFunc", (VALUE (*)(...)) MyFunc, -1);

    //get a reference to ERB
    ID sym_erbclass = rb_intern("ERB");
    VALUE erbclass = rb_const_get(rb_cObject, sym_erbclass);
    //list of arguments to initialise erb (1 arg)
    VALUE erbargv[1];
    erbargv[0] = rb_str_new2(erb_line.c_str());
    VALUE myerb = rb_class_new_instance(1, erbargv, erbclass);
  
    //prepare the result
    VALUE resultargv[0];
    VALUE result = rb_funcallv(myerb, rb_intern("result"), 0, resultargv);
  
    cout << string(RSTRING_PTR(result), RSTRING_LEN(result));

    /* destruct the VM */
    return ruby_cleanup(0);
  
}

Un peu plus long n'est-ce pas ? Mais ce n'est pas tant sorcier que cela, c'est juste pénible à chercher dans la doc quand on est dans un cas de figure que les gens rencontrent apparement peu et donc ne documentent guère plus.

Il existe néanmoins des subtilité induite par c++, qui est par exemple plus fortement typé que c, ce qui explique qu'il faille caster de manière judicieuse le pointeur d'une fonction c++ que l'on veut enregistrer dans ruby.

La compilation ne pose pas de problème majeur, le plus dur et de localiser les headers dont dépend <ruby.h> pour les inclures dans le path (ci dessous la ligne que j'ai employé sur ubuntu 15.04):

g++ --std=c++11 main.cpp -o essai -I/usr/include/ruby-2.1.0 -I/usr/include/x86_64-linux-gnu/ruby-2.1.0/ -lruby-2.1

Vous me direz, tant d'efforts pour pas grand chose ? Je vous rapelle que le but était de pouvoir exploiter les données contenues dans une application c++, hors vous remarquerez que MyFunc peut tout à fait servir d'accesseur ! Ainsi nous disposons de toutes les cartes pour créer des applications exploitant erb.

La prochaine fois je vous montrerai comment cross-compiler une telle application pour Windows depuis Linux !

lundi 9 février 2015

Pourquoi je soutiens bec et ongles l'initiative pour remplacer la TVA par une taxe sur les énergies ?

Pourquoi je soutiens bec et ongles l'initiative pour remplacer la TVA par une taxe sur les énergies ?

Le texte de l'initiative



C'est vrai que quand on me l'a présentée, je me suis dit: "mais quelle bêtise, les gens ne vont jamais vouloir d'un truc pareil." Comment j'ai changé d'avis ?

Premièrement, j'ai appris plus en détail ce qu'était la TVA. À l'époque, je savais déjà que c'était une taxe payée par les entreprises et qui se répercutait ensuite sur le prix et donc le consommateur final. Ayant fait un peu de compta, je savais déjà quel enfer pouvait être la TVA pour les comptables (comptabiliser celle qu'on a payée, celle qu'on doit payer et ce pour chaque petite opération de transformation).

Le premier scoop qu'on m'a asséné à l'époque, naïf lycéen que j'étais, c'est que toute cette complexité avait un coût: car en plus, on doit subir moult contrôles et pouvoir ensuite se justifier sur le moindre achat, et ce, pour les beaux yeux de l'État.

Le second scoop qu'on m'a asséné, c'est qu'il fallait supprimer une autre taxe pour obtenir un vrai effet incitatif avec une taxe pour l'environnement, en tout cas sur les énergies fossiles, car, il faut le savoir, la demande en énergie est passablement inélastique. Cela veut dire quoi ? Cela veut simplement dire que la demande va réagir très peu à une augmentation du prix.

Enfin, et cela je le savais déjà, les quantité disponible de pétroles sont limitée et ce, sans parler des impacts sinistrement négatifs de la consommation d'énergie non-renouvelable. (Un exemple)


Ok, mais pourquoi ne pas prendre une autre solution comme attendre ou une taxe en plus ?

Alors voici la liste de mes argument concernant...

attendre:


  • Attendre ne peut pas permettre à la situation de changer. Du pétrole ne va pas apparaître. Les énergies renouvelables arrivent également à maturité. Il est utopique de croire que l'on arrivera un jour à la même concentration énergétique que l'uranium ou le pétrole et de beaux systèmes centralisés avec le renouvelable.

  • Attendre, c'est prendre le risque toujours plus présent d'une flambée des prix du pétrole qui nous forcerait à changer en urgence.

  • Attendre, c'est relâcher plus de pollution dans l'atmosphère. Outre les effets du changement climatique, les résidus de combustion ont d'autres effets très amusants sur la santé (mais pas agréable pour nous).


Une autre taxe ? La question mérite de se poser! Pourquoi la TE serait meilleures qu'une autre ?

Hé bien justement, car elle remplace la TVA. Et donc:


  • Elle libère les entreprises d'un fardeau administratif. En effet le prélèvement de la TVA est coûteux: 1,8 milliards qui pèsent essentiellement sur les petites entreprises pourtant le nerf de la guerre de l'innovation.

  • Libère les entreprises d'une taxe sur le travail et l'innovation. En effet la TVA oblige à l'innovation d'être 8% plus rentable car elle pèsera sur les prix que l'innovation devra justifier (ou au contraire limitera l'effet de l'innovation pour une baisse des prix)

  • Elle ne représente qu'une redistribution plus intelligente de la facture fiscale. Au final les citoyens ne paieront pas plus dans l'ensemble. Les gens ont peur que cela retombe le plus sur eux mais il ne dépend que d'eux pour s'adapter! Et comme la demande pour s'adapter va augmenter, le besoin en innovation va grandir.


Or, l'innovation c'est le nerf de la guerre contre le gaspillage d'énergie. J'aime me baser sur les explications contenues dans cet exposé, qui explique et démontre que la croissance aujourd'hui, on ne l'a obtenue qu'en ayant les moyens de brûler plus d'énergie à peu de choses près. Bien sûr je ne suis pas entièrement d'accord. L'efficacité énergétique a augmenté aussi et contribué à cette croissance (ainsi un gramme de CO2 émis vous apporte plus de kWh aujourd'hui qu'il y a 40 ans). Mais cela risque de s'inverser bientôt, les nouveaux type de pétroles (schiste, sables bitumineux) et l'augmentation de la part du charbon dans le mix énergétique vont faire diminuer à nouveau l'efficacité énergétique. Par exemple cet article en parle


Or, il y a un autre point sur lequel je ne suis pas d'accord avec lui. Si les ressources énergétiques que l'on a aujourd'hui à disposition correspondent à 200 esclaves, on ne vit pas comme si on avait 200 esclaves à notre disposition et pour cause: on gère l'énergie comme des tordus, en la gaspillant allègrement. Les prochaines opportunités de croissance, à vrai dire celles qu'il nous reste, sont dans l'innovation pour l'efficacité énergétique et les énergies renouvelables. Si on gère correctement notre système économique pour ne pas gaspiller l'énergie que l'on y fait entrer alors on pourra encore croître là dessus.

Par contre, je pense que le risque d'avoir des guerres de l'énergie ou des camps de l'horreur en tout genre avec des réfugiés climatiques n'est pas à exclure. Il n'y a qu'à voir ce qui s'est passé en Irak. Rendre la suisse autonome n'en sera que plus sûr.

Au final les arguments des opposants, bien qu’apparemment convaincants sont soit des mensonges, soit du manque d'information.

Prenons le cas de l'essence annoncée à 5 francs suisses ! Selon les chiffre de 2013 de l'OFEN, en suisse ont été utilisées comme énergies non renouvelables

  • 10'900'000 tonnes de produits pétroliers divers soit 109'000'000'000 kWh

  • 59'300'000'000 kWh d'électricité dont 40% non ENR soit 23'720'000'000 kWh

  • 33'600'000'000 kWh sous forme de gaz soit 33'600'000'000 kWh


soit 166'320'000'000 kWh, avec 21 mia de francs de rentrée fiscale pour la TVA le prix du kWh augmenterai de 12.626 centimes. Le prix de l'essence ne grimperait que de 1.20 chf (et encore à déduire la TVA actuelle soit en réalité à peine 1.10 d'augmentation).

L'idée étant que si la taxe passe, du jour au lendemain le prix de l'essence grimperai à 5 chf... hahaha, ils me font rire. S'il grimpait aussi haut la consommation d'énergie fossile aurait été divisée par plus de 2. Mis à part le fait que la situation serai radicalement différente et que donc il est dur d'imaginer où l'on en sera à ce moment là, cela n'arrivera pas avant de nombreuses années. En effet la demande de combustible fossile est très inélastique et donc varie peu et lentement suite à un changement de prix important.

Et quand on y sera arrivé, le tournant énergétique sera tellement bien engagé que l'on pourra sans problème replacer la TE par autre chose. Personnellement j'aimerai bien adapter l'idée (qui est bien foutue) aux produits écotoxiques qui empoissonnent notre environnement (à tout hasard).

S'il suffisait d'introduire une taxe pour que l'effet soit immédiat (ou quasi immédiat) la gestion des états en serait grandement facilitée !


En claire une idée bonne quoique déstabilisante, combattue par la peur et le mensonge ! Personnellement j'espère que cela va passer. Pour que vous puissiez continuer de vous faire une opinion je vous invite à continuer sur ce blog qui est un peu plus détaillé.

lundi 24 novembre 2014

[retour de convention] les 27èmes rencontres du club pythagore

Alors je serai bref au niveau du texte j'ai (et surtout mon ordinateur, qui a ramé pendant 12h ^^ ) assez travaillé sur la video souvenir ;P



Néanmoins une petite explication s'impose quand même du coup...

Les rencontres du club pythagore sont une sympathique convention avec pas trop de monde, un super buffet et une super ambiance qui se déroule à Provin. Nous étions invités avec l'équipe la Chaux-de-Fonds 1904 à venir présenter notre jeu. J'ai donc fait jouer deux parties de crimes le samedis la première étant allé comme sur des roulettes, j'étais très en forme et es joueurs bien dans l'ambiance, la seconde un peu plus dur car joué tard le soir.

De plus, durant la première partie... ils ont finis par faire ce que tout le monde attendais mais chut... demandez moi de vous faire jouer le scénario plutôt que je ne vous le spoil ^^

Le dimanche je me suis essayé à friponnes (le JDR est encore en dévellopement, mais vous trouverez des livres dans cet univers sur ce site). Personnellement je me suis éclaté. Le jeu se base sur le système FU qui est à la fois littéral et léger. Les joueurs ont une très grande influence sur le mode de résolution du scénario, ce qui approche le jeu d'un système narratif, mais avec un système classique et peu rebutant pour les habitués de JDR "Canoniques".

Je dirai donc que j'ai tellement rigolé (j'ai crus que j'allais me casser les côtes aux moments les plus croustillants), que les morpions peuvent êtres une arme de destruction massive et que je n'en dirai pas plus... bandes d'indiscrets fripons curieux ;P

Bon, après le jeu ne bat largement pas Romance Érotique au point de vue des détails si ça peut vous rassurer... il n'est juste pas à faire jouer au personnes de moins de 16 ans (pire encore si on joue avec des lustucrus plus vieux qui n'ont pas de retenue ;P )

Mais je vous le recommande si vous aimez les jeux légers où l'on ne se prends pas trop la tête!

lundi 12 mai 2014

Chimériades!

Je serai pas le seul à faire un compte rendu des chimériades. Pour les amateurs de longs discours je vous renvoie au post d'Alias, qui a écrit plus de 1000 signes et que je ne vais en aucun cas imiter ;P

http://alias.codiferes.net/wordpress/index.php/chimeriades-2014/?fb_action_ids=10152167241088865&fb_action_types=news.publishes&fb_ref=pub-standard&fb_source=aggregation&fb_aggregation_id=288381481237582

Comme en plus mon appareil photo est bientôt totalement knock out je l'ai pas pris, cette année je me suis ramené avec ma caméra et donc ce message n'a d'autre but que de partager avec vous le montage que j'ai obtenu:



Le lien pour la musique: http://www.jamendo.com/fr/artist/370191/wizart-music

En passant j'ai gagné un JDR sur cette conv, je crois que je vais réaliser ma première critique sur ce blog (dès que j'aurais le temps ^^ )!


Et surtout! Un immense merci au orgas: elle est géniale votre conv!


mardi 25 mars 2014

[retour à froid] Ludesco

Il y a un truc que je n'aime pas avec les conv... c'est le besoin de se remettre à jour après coup! Ça fait 2 semaines que ludesco et terminé et j'ai toujours pas fait de retour... par nécessité scolaire.

Maitenant que j'ai un peu de temps (ce qui explique que ce message soit rédigé à 10h du soir) juste un rapide retour.

C'était ma première année dans le comité, petit jeune de service (comme d'hab ^^ ) et resp JDR. J'ai d'ailleurs pas eu beaucoup de temps pour faire des jeux de plateaux, occupés que j'étais à courir partout pour les JDR.



Mais ça en valait la peine. Pour le 5ème anniversaire on a eu un programme JDR étoffé comme jamais. Et la sortie du jeu la Chaux-de-Fonds 1904 est venue couronné le tout (pour ceux qui l'auraient pas encore obtenu... contactez moi si vous avez mon adresse et sinon regarder dans votre magasin de jeu préféré et même dans votre librairie, le jeu devrait y arriver tantôt s'il n'y est pas déjà!).

Ha oui, aussi de superbe partie au musée d'histoire naturelle, la convention avance ses pions dans le domaine du "JDR à valeur ajoutée". Un concept que j'adore personnellement! Mais comme il est tard et que j'en ai marre d'écrire je vous donne juste la photo:




Bien ludiquement et à l'année prochaine (du 13 au 15 mars)

mercredi 22 janvier 2014

Ludesco c'est bien, mais combien bien?

Hello, dsl de ne pas faire démarrer ce blog au quart de tour, il me tiens à coeur mais je manque de temps (vous allez bientôt savoir pourquoi). Mais bon, j'ai une bonne occasion puisqu'il se prépare de part chez moi une super convention de jeu en tout genre: Ludesco



Ludesco faut y venir, c'est bien! Mais comme je vous vois sceptique et que vous et moi aimons les chiffres je vais essayer de répondre à la question "combien c'est bien?"

Après de très longue recherches nous sommes enfin parvenu à mettre sur pied un modèle pour compter combien Ludesco sera bien.

Implémenté en c++ cela donne (cclcb veut dire "pour compter combien Ludesco c'est bien!" ):

 unsigned int cclcb(unsigned int annee, unsigned int scoreInitial = 2){

      if(annee){
            if(scoreInitial)
                  return cclcb(annee-1, cclcb(annee, scoreInitial-1));
            else
                  return cclcb(annee-1, 1);
      }
      else
            return scoreInitial+1;

}

Sans entrer dans les détails on recalcule récursivement le score de l'année en cour avec le score de l'année passée et une estimation du score de l'année en cour (qui est calculée récursivement et vaut au minimum 1. Pour ceux qui avaient pas remarqué cela correspond à la fonction d'Ackermann.

Bon, visiblement ceux qui voulaient des chiffres sont servis, pour les autres qui on pas tiqué je vous invite à lire cette article de wikipédia, juste ce qui faut pour frimer au repas de noël. Bien sûr les auteurs originaux de la fonction ne se doutaient pas qu'elle servirait un jour à estimer la qualité d'un événement exceptionnel!

Et en plus je suis dans l'équipe des JDR*, alors restez branchés parce qu'il va falloir trouver des MJ et des joueurs pour une année encore plus exceptionnelle que les précédentes (la 5ème si vous voulez essayer le calcul)! Plus de détails bientôt!

*si si, c'est entre autre pour ça que je n'ai pas beaucoup de temps, mais c'est tellement cool que je me pardonne ^^

mercredi 28 août 2013

Question de bits et de bytes

Mis à part que les pionniers de l’informatique auraient dut se préoccuper du français quand ils ont nommée leurs unités logique voici le problème que je me posais initialement:

Un booléen est habituellement stocké dans un octet (soit un unsigned char) alors qu'il ne peut prendre que deux états. Pour un seul booléen ou des milliers des booléens ça reste un gaspillage acceptable sur les ordinateurs modernes, où la mémoire ne manque pas. Mais pour certaines applications (par exemples de larges filtres de Bloom) il est souhaitable de compacter la place occupées par les milliers de booléens que l'on veut instancier. En d'autre thermes, peut-on instancier un tableau de bits?

Réponse, pas de base, il faut quitter sa zone de confort avec les jolis opérateur qu'on nous a appris en primaire ( + - ÷ × ) et s'attaquer à ces inquiétant opérateur dit bit à bit (et il est interdit de penser à une partouze)  ( & | ^ << >> ).

Heureusement ce tutoriel est là pour vous aider, on va même réaliser ensemble un jolis objet c++ qui va gérer tout ça pour nous! Voyons d'abords ces fameux opérateurs qu'on va utiliser:

&

AND, "et" logique, renvoie un bit à 1 si et seulement si les deux bits de même poids valent 1 sur les deux paramètres passés:

unsigned int a = 4 & 7;  //a = 4
unsigned int b = 7 & 9; //b = 1
unsigned int c = 4 & 9; //c = 0

unsigned int oct = 0203 & 0205; //oct = 0201
unsigned int hex = 0x000F02 & 0x00420F; //hex = 0x000202;


Vous l'aurez remarqué la clé du problème c'est la décomposition des nombre en puissance de deux. Pour accéder au nième bit d'un entier il suffit donc de réaliser nombre & (2 à la puissance n).

|

OR, "ou" simple fonctionne de la même manière mais il lui suffit qu'il seul des deux bits de même poids soient à 1 pour renvoyer 1:

unsigned int a = 4 | 7;  //a = 7
unsigned int b = 7 | 9; //b = 15
unsigned int c = 4 | 9; //c = 13

unsigned int oct = 0203 | 0205; //oct = 0207
unsigned int hex = 0x000F02 | 0x00420F; //hex = 0x004F0F;


^

XOR, "ou" exclusif, renvoie 1 si et seulement si un seul des bits de même poids vaut 1:

unsigned int a = 4 ^ 7;  //a = 3
unsigned int b = 7 ^ 9; //b = 14
unsigned int c = 4 ^ 9; //c = 13

unsigned int oct = 0203 ^ 0205; //oct = 0006
unsigned int hex = 0x000F02 ^ 0x00420F; //hex = 0x004C0C;


<< et >> 

représentent un décalage à gauche ou à droite ce qui revient à multiplier ou diviser par deux autant de fois que spécifié ( et dans la limite de la taille du type utilisé).

unsigned int a = 2 << 2;  //a = 8
unsigned int b = 1 << 3; //b = 8
unsigned int c = 2 >> 1; //c = 1


Leur principale utilité, combinés aux opérateurs précédents, est d'accéder à un bit donné.

unsigned int a = 1 << 0;  //a permet d'inspecter le bit 0
unsigned int b = 1 << 5; //b permet d'inspecter le bit 5

Il fut un temps les processeurs ne pouvaient pas réaliser directement les opérations arithmétiques de base, il fallait les implémenter grâce à ces opérateurs bits à bits. Par exemple le bon vieil algorithme d'addition en colonne devenait (la représentation assumée est celle dite complément à deux, la charge de détecter les dépassements n'est pas assumée par la fonction):

 int additionner (int pN1, int pN2){

      int n1 = pN1;
      int n2 = pN2;

      int r1 = n1 ^ n2; //addition directe
      int r2 = (n1 & n2) << 1; //retenue

      if(!r1)
            return r2;
      else if (!r2)
            return r1;
      else
            return additionner (r1, r2);

}


Donc on peut s'offrir un tableau de booléen compressé, voici en c++:

Définition:

 class BinaryKeeper{

    public:


        /** Default constructor */
        BinaryKeeper(unsigned int pSize);
        /** Default destructor */
        virtual ~BinaryKeeper();
        /** Copy constructor
         *  \param other Object to copy from
         */

        BinaryKeeper(const BinaryKeeper& other);
        /** Access size
         * \return The current value of size
         */

        unsigned int Getsize() const{ return size; }

        bool InIndex(unsigned int index) const;
        char CharInIndex(unsigned int index) const;

        void SetIndex(unsigned int index, bool pState);


    private:


        unsigned int size; //!< Member variable "size"
        unsigned char* datas; //!< Member variable "datas"


};


Premièrement le constructeur, il va essentiellement instancier un tableau d'unsigned char et le remplir de 0. Ce type offre l'avantage d'être de taille constantes selon les systèmes:

/** Default constructor */ 
BinaryKeeper::BinaryKeeper(unsigned int pSize){

    //ctor

    size = pSize;
    unsigned int cSize = size/8 + 1;

    try{

        datas = new unsigned char [cSize];

        for(unsigned int k = 0; k <
cSize; k++){
            datas[k] = 0;
        }

    }catch ( const std::bad_alloc & ) { // erreur d'allocatation.

        delete [] datas;
        size = 0;

    }
 

}

Ce code n'est pas très compliqué. Notez bien que pour être certain d'avoir assez de place pour inscrire le nombre de bits demandé qui n'est pas forcément un multiple de 8 vous devez ajouter un octet à la taille de votre tableau. Si ce dépassement anecdotique vous ennuie vous pouvez corriger size, personnellement j'alloue quelques bit de plus mais je tiens à ce que mon objet  encapsule la taille demandée.

Le destructeur lui, va juste libérer les allocations dynamiques:

/** Default constructor */ 
BinaryKeeper::~BinaryKeeper(){

    //dtor
 

    delete [] datas;
 

}


Viennent ensuite les accesseurs,  si accéder à une char donnée se fait de manière simple (libre à vous de définir un comportement quand vous dépasser la taille du tableau, personellement dans ce cas je renvoie le plus haut indice disponible). Pour accéder à l'état (true | false) d'un bit donné ça se corse un peu.

char BinaryKeeper::CharInIndex(unsigned int index) const{

    if (index <= size/8)
        return datas[index];
    else
        return
datas[size];
}


bool
BinaryKeeper::InIndex(unsigned int index) const{

    unsigned int i = index;

    if( i >= size)
        i = size-1;

    unsigned int cIndex = i >> 3 ;
    unsigned int cInside = i & 7 ;

    unsigned char v = datas[cIndex];

    unsigned char c = 1 << cInside;

    return (bool) (v & c);

}

Les index de notre tableau de bits fonctionnent comment ceux d'un tableau classique. Le premier bit est le bit de poids 0 (2^0) du char 0. Le dernier est donc le size-1 ème bits. On corrige donc l'index s'il est trop haut (on pourrait aussi lancer une exception, renvoyer faux ou vrai par défaut ... ).

Ensuite viennent ces deux lignes assez mystérieuses (je vous aide un peu et vous donne les équivalents classiques):

    unsigned int cIndex = i >> 3 ;
    unsigned int cInside = i & 7 ;


    //équivalent:
 

    unsigned int cIndex = i / 8 ;
    unsigned int cInside = i % 8 ;

cIndex est le char que l'on va inspecter, cInside le poids du bit à inspecter à l'intérieur. On les obtient le plus logiquement du monde en divisant par 8 et en prenant le modulo par 8 de l'indice demandé. Mais comme 8 est une puissance de 2 il y a plus "simple" (du moins en temps de calcul pour l'ordinateur). Diviser par 8 revient à diviser par 2^3 soit de décaler 3 fois à droite. Prendre le modulo revient à effacer tout les bits sauf ceux de poids 0, 1 et 2 ce qui se fait grâce à l'opérateur & 7.

unsigned char c = 1 << cInside;

 c servira à accéder au bit souhaité. Ce que l'on fait à la ligne suivante grâce à &:

return (bool) (v & c);


Enfin détaillons la fonction de changement d'état d'un bit donné, j'ai choisi volontairement de créer une fonction qui change le bit vers un état spécifié mais il serait possible d'en créer une qui inverse simplement l'ancien état:

void BinaryKeeper::SetIndex(unsigned int index, bool pState) {

    unsigned int i = index;

    if( i >= size)
        i = size-1;

    unsigned int cIndex = i >> 3 ;
    unsigned int cInside = i & 7 ;

    unsigned char c = 1 << cInside;


    if (pState){ // si on veut mettre l'état à true
        datas[cIndex] |= c; //alors on le met à 1
    } else { // si on veut mettre l'état à false;
        c ^= 255; //on place un zéro sur le bit du poids qui nous intéresse.
        datas[cIndex] &= c; //on le met à 0.
    }
}


Bien sûr cet objet reste relativement simple dans sa conception, il ne gère pas d'exceptions, ne permet pas d'utiliser d'itérateurs, etc... Néanmoins il réalise son travail correctement (du moins de ce que j'ai put tester) quand il s'agit de gérer un filtre de bloom ou un très grands tableau de booléens tout en économisant la mémoire. Il sera par contre légèrement plus lent qu'un simple bool*.

Libre à vous de l'améliorer, perso je ne le ferai que si j'en ai l'utilité. Puisque pour l'instant il me convient ainsi!