<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-949706588497831852</id><updated>2012-02-02T20:58:10.032+01:00</updated><category term='xml'/><category term='matériel'/><category term='oeuf'/><category term='sons'/><category term='postgres'/><category term='emacs'/><category term='client'/><category term='3d'/><category term='web'/><category term='blender'/><category term='médoc'/><category term='économie'/><category term='art'/><category term='test'/><category term='monde'/><category term='programmation'/><category term='sql'/><category term='git'/><category term='glsl'/><category term='projet'/><category term='mmorpg'/><category term='adh'/><category term='berenice'/><category term='debian'/><category term='ocaml'/><category term='c++'/><category term='humeur'/><title type='text'>L'Aube des Héros</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default?start-index=101&amp;max-results=100'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>344</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-7846078692692564706</id><published>2012-01-29T13:41:00.003+01:00</published><updated>2012-01-29T13:49:44.421+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='médoc'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>L'oeil extérieur</title><content type='html'>Depuis que quelques bonnes âmes essayent Médoc, je retrouve nombre de petites limitations, ou de cas particuliers que j'avais ignoré un peu rapidement. Le résultat, c'est que le logiciel s'améliore lentement, mais sûrement. &lt;br /&gt;&lt;br /&gt;Ce sont des choses bêtes: la localisation, par exemple, qui envoyait des dates en français à la base de données. Ou le support multi-devices: Sane ne reconnait que mon scanner HP, j'ai donc paresseusement simplifié Médoc en prenant le premier device disponible. Mais une simple webcam, par exemple, est considéré comme étant un device supplémentaire, et tout d'un coup, l'hypothèse ne tient plus.&lt;br /&gt;&lt;br /&gt;La morale de cette histoire, c'est:&lt;br /&gt;- &lt;a href="https://en.wikipedia.org/wiki/Eating_your_own_dog_food"&gt;Eat your own dog food&lt;/a&gt;&lt;br /&gt;- Mais faites tester par d'autres!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-7846078692692564706?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/7846078692692564706/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=7846078692692564706' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7846078692692564706'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7846078692692564706'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2012/01/loeil-exterieur.html' title='L&apos;oeil extérieur'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-637058371174141401</id><published>2012-01-22T20:41:00.002+01:00</published><updated>2012-01-22T20:46:14.644+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='oeuf'/><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Un client Twitter en OCaml</title><content type='html'>Pourquoi s'arrêter en si bon chemin? Voici un nouvel &lt;a href="https://github.com/smallduckinette/duck_eggs/tree/master/mltwitstream"&gt;œuf de canard&lt;/a&gt;: le même client Twitter pour l'API stream, mais cette fois-ci en OCaml. Utilisant &lt;a href="http://martin.jambon.free.fr/yojson.html"&gt;Yojson&lt;/a&gt; et &lt;a href="http://sourceforge.net/projects/ocurl/"&gt;OCurl&lt;/a&gt;, c'est le port copie conforme du client C++.&lt;br /&gt;&lt;br /&gt;Si jamais je me décidais à enregistrer les messages dans une base de données, c'est plutôt à partir du client OCaml que je continuerais.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-637058371174141401?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/637058371174141401/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=637058371174141401' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/637058371174141401'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/637058371174141401'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2012/01/un-client-twitter-en-ocaml.html' title='Un client Twitter en OCaml'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4982282749483766929</id><published>2012-01-17T17:36:00.002+01:00</published><updated>2012-01-17T17:39:40.257+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='oeuf'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Oeuf de canard - C++ et zlib</title><content type='html'>Un vieil œuf de canard que je viens de poster: mon vieux wrapper zlib est maintenant dans le &lt;a href=https://github.com/smallduckinette/duck_eggs/tree/master/zstream&gt;nid douillet de Github&lt;/a&gt;, avec deux binaires triviaux pour la compression et la décompression.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4982282749483766929?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4982282749483766929/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4982282749483766929' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4982282749483766929'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4982282749483766929'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2012/01/oeuf-de-canard-c-et-zlib.html' title='Oeuf de canard - C++ et zlib'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4561922803990917690</id><published>2012-01-13T23:34:00.004+01:00</published><updated>2012-01-13T23:41:39.430+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='médoc'/><title type='text'>Peaufinage</title><content type='html'>Quelques améliorations de Médoc: tout d'abord, je rends l'OCR optionnel, puisque la version 2 de Tesseract, empaquetée sous Debian, est assez buggée et crashe régulièrement. Si un document ne passe pas, allez donc désactiver l'option.&lt;br /&gt;&lt;br /&gt;Ensuite, j'ai tenté d'améliorer le look de la boite de dialogue du scan: la bibliothèque Sane contient déjà la notion de groupe, il suffisait donc de recoller les morceaux. Une boite de dialogue typique ressemble à ça:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-JMeTjbWCSVI/TxCykfLKbSI/AAAAAAAAEhg/Ujqa12ijOeE/s1600/scanner.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 282px; height: 320px;" src="http://2.bp.blogspot.com/-JMeTjbWCSVI/TxCykfLKbSI/AAAAAAAAEhg/Ujqa12ijOeE/s320/scanner.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5697249868537031970" /&gt;&lt;/a&gt;&lt;br /&gt;Notez également que la barre de progression est maintenant intégrée, ce qui l'évite de surgir sur le bureau alors que l'on est en train de faire autre chose pendant un long scan.&lt;br /&gt;&lt;br /&gt;Un gros morceau sera de revoir en détail l'ordre des contrôles dans chaque boite de dialogue, afin de simplifier la navigation par la touche Tab.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4561922803990917690?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4561922803990917690/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4561922803990917690' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4561922803990917690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4561922803990917690'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2012/01/peaufinage.html' title='Peaufinage'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-JMeTjbWCSVI/TxCykfLKbSI/AAAAAAAAEhg/Ujqa12ijOeE/s72-c/scanner.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-9008223021787278763</id><published>2012-01-08T19:11:00.003+01:00</published><updated>2012-01-17T17:40:39.761+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='oeuf'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Streaming API Twitter</title><content type='html'>Non, je ne me suis pas encore vendu aux médias sociaux, mais puisque je pourrais en avoir besoin bientôt, je me suis lancé dans l'écriture d'un tout petit programme en C++ destiné à lire les feeds Twitter en temps réel. Combinant curl et json_spirit, suffisamment grand pour ne pas être pratique à poster, mais suffisamment petit pour ne pas valoir un projet à lui tout seul, c'était le candidat parfait pour mon dépôt "Œufs de canard" dont je parlais dans un post précédent (j'avais en effet déjà une idée derrière le bec).&lt;br /&gt;&lt;br /&gt;Le code se trouve &lt;a href="https://github.com/smallduckinette/duck_eggs/blob/master/twitstream/twitstream.cpp"&gt;ici&lt;/a&gt;. L'on lancera le programme ainsi:&lt;br /&gt;&lt;br /&gt;./twitterstream -u username -p password -k mot1 -k mot2 -k mot3...&lt;br /&gt;&lt;br /&gt;Et devraient surgir à l'écran les messages filtrant sur un des mots-clé passés dans les options -k.&lt;br /&gt;&lt;br /&gt;Je suis impressionné par le débit: sur des mots relativement courants, ça descend à toute vitesse.&lt;br /&gt;&lt;br /&gt;Je me tâte maintenant à ajouter une couche de persistance vers une base de données... Peut-être après Médoc v2!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-9008223021787278763?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/9008223021787278763/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=9008223021787278763' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/9008223021787278763'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/9008223021787278763'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2012/01/streaming-api-twitter.html' title='Streaming API Twitter'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-8158942178202538963</id><published>2012-01-08T19:06:00.003+01:00</published><updated>2012-01-17T17:40:21.608+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='oeuf'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Oeufs de canard</title><content type='html'>J'inaugure mon nouveau dépôt &lt;a href="https://github.com/smallduckinette/duck_eggs"&gt;Œufs de canard&lt;/a&gt;, où je placerai mes programmes de test, ce qui sera plus simple que de faire d'interminables listings plus ou moins bien formatés ici. Plus de contenu, moins de blabla, voici mes vœux pour ce blog en 2012 (vous allez me dire, ça commence bien...).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-8158942178202538963?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/8158942178202538963/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=8158942178202538963' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8158942178202538963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8158942178202538963'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2012/01/oeufs-de-canard.html' title='Oeufs de canard'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4254442580035325708</id><published>2012-01-07T00:27:00.001+01:00</published><updated>2012-01-07T00:27:40.169+01:00</updated><title type='text'>J'oubliais...</title><content type='html'>Et bonne année, aussi!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4254442580035325708?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4254442580035325708/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4254442580035325708' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4254442580035325708'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4254442580035325708'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2012/01/joubliais.html' title='J&apos;oubliais...'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-6961173216975115161</id><published>2012-01-06T23:57:00.004+01:00</published><updated>2012-01-07T00:27:04.544+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Covariance</title><content type='html'>C'est étrangement une fonctionnalité qui semble relativement peu connue des programmeurs C++: la covariance des types de retours dans les fonctions surchargées.&lt;br /&gt;&lt;br /&gt;L'exemple standard est la déclaration d'une méthode "clone", qui renvoie une copie de l'objet. Prenons une classe A:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class A&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  virtual ~A();&lt;br /&gt;  virtual A * clone() const;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Maintenant, comment écrire une classe B dérivant de A, de manière à ce que la méthode clone fonctionne, c'est à dire renvoie une instance de B si le type sous-jacent est B? Ou plus exactement, quel devrait être le type de retour de la méthode clone de B?&lt;br /&gt;&lt;br /&gt;L'on peut bien entendu retourner A. C'est clair, net et précis lorsque l'on travaille avec A, mais c'est dommage lorsque l'on travaille directement avec B: appeler clone renvoie un pointeur sur A, alors que l'on sait pertinemment que c'est un B, et on doit donc le caster vers B pour travailler avec.&lt;br /&gt;&lt;br /&gt;Profitons donc de cette fonctionnalité introduite dans C++98, qui dit que si une méthode virtuelle renvoie un pointeur, l'on peut surcharger cette méthode avec un type de retour pointeur vers un objet dérivé. L'on écrira donc:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class B : public A&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  B * clone() const;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Et la méthode clone fonctionnera exactement de la manière désirée.&lt;br /&gt;&lt;br /&gt;Il est à noter que le type de retour peut-être différent du type parent: si A dérive de B, et C dérive de D, une méthode de A retournant C peut être surchargée dans B comme retournant D.&lt;br /&gt;&lt;br /&gt;Il est à noter également que malheureusement, cette fonctionnalité devient de moins en moins utile: de nos jours, il est de plus en plus rare de renvoyer un pointeur à poil, et il n'est pas possible d'obtenir le même résultat avec un shared_ptr, par exemple. Dans ce cas, il faudra renvoyer systématiquement le type parent, et faire un cast.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-6961173216975115161?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/6961173216975115161/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=6961173216975115161' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6961173216975115161'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6961173216975115161'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2012/01/covariance.html' title='Covariance'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-8416142532903003666</id><published>2011-12-29T20:47:00.000+01:00</published><updated>2011-12-29T20:48:31.233+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Yaaaa!</title><content type='html'>Vu la vie de Genghis Khan hier à la télé... Ça me donne envie de rejouer à Mount &amp; Blade. Pas bon pour le développement, ça!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-8416142532903003666?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/8416142532903003666/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=8416142532903003666' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8416142532903003666'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8416142532903003666'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/12/yaaaa.html' title='Yaaaa!'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-6748848276676934752</id><published>2011-12-23T19:49:00.003+01:00</published><updated>2011-12-23T20:05:09.241+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='médoc'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>C'est maintenant que ça commence</title><content type='html'>De très bons retours de ma présentation de Médoc sur LinuxFr (&lt;a href="https://linuxfr.org/users/small_duck/journaux/m%C3%A9doc-un-d%C3%A9p%C3%B4t-de-documents-fait-maison"&gt;ici&lt;/a&gt; et &lt;a href="https://linuxfr.org/news/m%C3%A9doc-un-d%C3%A9p%C3%B4t-de-documents-fait-maison"&gt;là&lt;/a&gt;). Merci à tous les commentateurs! J'en retire plus particulièrement ces quelques points:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Tout d'abord, faire fonctionner Médoc sur la machine de quelqu'un d'autre est un sacré défi. L'on a découvert des soucis liés aux locales, et je soupçonne peut-être certains problèmes 32/64 bits. Enfin, les autres scanners ont des options spécifiques que je n'avais pas implémentées&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Ensuite, utiliser du JPG pour mes images n'est probablement pas l'idée du siècle: en effet, un format comme &lt;a href="http://en.wikipedia.org/wiki/DjVu"&gt;DjVu&lt;/a&gt; semble bien plus approprié. J'espère pouvoir réduire significativement la taille de la base, qui devient de plus en plus difficile à sauvegarder.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Enfin, il semble pertinent de réintégrer la reconnaissance de caractères, d'autant plus que Debian fournit maintenant la bibliothèque &lt;a href="http://www.gnu.org/software/ocrad/"&gt;ocrad&lt;/a&gt;. Les autres solutions de reconnaissance de caractères ne fournissaient pas de bibliothèque C, ce qui m'avait refroidi.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Pas mal de boulot devant moi, donc. Tout d'abord, je vais, ou plutôt, je suis en train d'installer une Ubuntu 32 bits avec une locale française dans une machine virtuelle, pour tenter de reproduire certains bugs qui m'ont été signalés. Ensuite, je vais m'attaquer à l'amélioration du logiciel, ajout de fonctionnalités, et simplification du processus d'installation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-6748848276676934752?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/6748848276676934752/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=6748848276676934752' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6748848276676934752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6748848276676934752'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/12/cest-maintenant-que-ca-commence.html' title='C&apos;est maintenant que ça commence'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-1199533684914513100</id><published>2011-12-17T23:11:00.002+01:00</published><updated>2011-12-17T23:44:45.295+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='médoc'/><title type='text'>Médoc v1.0</title><content type='html'>Voilà, la dernière fonctionnalité de base vient d'être implémentée. La galerie étant maintenant munie de fonctions de sélection et de ré-ordonnancement, j'annonce que Médoc est pleinement utilisable, et tague donc cette version 1.0. Un peu de documentation sur l'installation est disponible sur le &lt;a href="https://github.com/smallduckinette/medoc/wiki/Installation-instructions"&gt;wiki du dépôt&lt;/a&gt; chez Github.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-1199533684914513100?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/1199533684914513100/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=1199533684914513100' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1199533684914513100'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1199533684914513100'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/12/medoc-v10.html' title='Médoc v1.0'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4044851197389989176</id><published>2011-12-14T23:08:00.005+01:00</published><updated>2011-12-14T23:40:50.006+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Murf</title><content type='html'>C'était bien la peine de passer une heure à faire des benchmarks. J'utilisais au boulot un boost::unordered_set d'entiers, avec des performances très décevantes, et l'on m'avait recommandé de remplacer la fonction de hachage par défaut avec &lt;a href="http://code.google.com/p/smhasher/"&gt;MurmurHash&lt;/a&gt;, avec des résultats tout à fait impressionnants. J'ai donc tenté de les reproduire à la maison, mais, étrangement, ce fut impossible... La version standard de l'unordered_set est légèrement plus lente dans la bibliothèque standard que chez Boost, mais surtout, l'utilisation de MurmurHash plombe les performances très sérieusement.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-d9bhLIKXNk4/TuklcaqYYhI/AAAAAAAAEgw/MKIjL7DW5S4/s1600/murmur_int.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 174px;" src="http://1.bp.blogspot.com/-d9bhLIKXNk4/TuklcaqYYhI/AAAAAAAAEgw/MKIjL7DW5S4/s320/murmur_int.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5686117174655607314" /&gt;&lt;/a&gt;&lt;br /&gt;Avec des chaines de caractères, par contre, MurmurHash commence à montrer les dents, et se montre plus rapide. Étrangement, dans ce cas, le hashset de la bibliothèque standard est plus rapide.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-ISBOV5inpdU/TukkpqB0zyI/AAAAAAAAEgg/yhuFIdHq2rE/s1600/murmur_string.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 186px;" src="http://2.bp.blogspot.com/-ISBOV5inpdU/TukkpqB0zyI/AAAAAAAAEgg/yhuFIdHq2rE/s320/murmur_string.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5686116302607142690" /&gt;&lt;/a&gt;&lt;br /&gt;J'ai dû rater quelque chose, mais quoi?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4044851197389989176?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4044851197389989176/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4044851197389989176' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4044851197389989176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4044851197389989176'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/12/murf.html' title='Murf'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-d9bhLIKXNk4/TuklcaqYYhI/AAAAAAAAEgw/MKIjL7DW5S4/s72-c/murmur_int.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-7515578000961484735</id><published>2011-12-04T00:22:00.004+01:00</published><updated>2011-12-04T00:41:25.370+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='médoc'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Une gallerie en wxWidgets</title><content type='html'>C'est basique, mais ça fait le boulot. Je viens de merger la branche gallerie dans la branche principale, maintenant que mon contrôle de galerie d'images est suffisamment fonctionnel. Voici la bête:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-1T9bVN9IdP8/TtqvbZZyM6I/AAAAAAAAEf0/XdMh-4QqECM/s1600/medoc_gallery.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 175px;" src="http://4.bp.blogspot.com/-1T9bVN9IdP8/TtqvbZZyM6I/AAAAAAAAEf0/XdMh-4QqECM/s320/medoc_gallery.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5682046765091664802" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Vu que je n'avais rien modifié dans ma branche principale, le merge a été particulièrement simple:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;git branch master &lt;= hop, de retour sur la branche princpale&lt;br /&gt;git merge gallery &lt;= on merge la gallerie, de fait un simple fast forward&lt;br /&gt;git branch -d gallery &lt;= et on détruit la branche devenue inutile&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Il reste encore à permettre le réarrangement des pages, et on devrait être fonctionnellement complet.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-7515578000961484735?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/7515578000961484735/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=7515578000961484735' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7515578000961484735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7515578000961484735'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/12/une-gallerie-en-wxwidgets.html' title='Une gallerie en wxWidgets'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-1T9bVN9IdP8/TtqvbZZyM6I/AAAAAAAAEf0/XdMh-4QqECM/s72-c/medoc_gallery.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-2901779507574622195</id><published>2011-12-01T23:44:00.003+01:00</published><updated>2011-12-02T00:10:50.824+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>En vrac</title><content type='html'>Pic de fréquentation aujourd'hui!&lt;br /&gt;&lt;br /&gt;Pour une raison que j'ignore, tout le monde (enfin, toutes proportions gardées) s'est précipité sur mon tutorial lwt, qui trainait sur le blog depuis 6 mois. La révolution fonctionnelle est en marche!&lt;br /&gt;&lt;br /&gt;Petit souci classique dans mon composant wxWidgets de galerie: je code en dur la largeur du composant, ce qui me permet d'y placer exactement le nombre d'images requis en largeur. Malheureusement, quand il y a trop d'images en longueur, la barre de défilement verticale apparait, ce qui réduit de quelques dizaines de pixels la largeur de la zone client, provoquant une très inutile barre de défilement horizontale (ça va, vous suivez?). Je pense tenter de corriger cela en forçant la barre verticale à être toujours présente, et ma zone client juste assez grande pour faire tenir mes images en largeur plus la barre.&lt;br /&gt;&lt;br /&gt;Ah, et je suis enfin plongé dans la partie "sociale" de Github. Je ne pensais pas y rencontrer quiconque, mais si, Dongorath, commentateur de ce blog, me "follow"! Si tu me lis encore, coucou Dongo :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-2901779507574622195?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/2901779507574622195/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=2901779507574622195' title='2 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2901779507574622195'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2901779507574622195'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/12/en-vrac.html' title='En vrac'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-7689081893326039036</id><published>2011-11-27T19:17:00.002+01:00</published><updated>2011-11-27T19:23:51.941+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Github - Ça vient doucement...</title><content type='html'>Aujourd'hui, je me suis mis à implémenter une vraie galerie d'images au lieu de la bête listbox, pour représenter la liste des images déjà importées. Ce fut donc l'occasion d'essayer de comprendre comment faire une branche sur git, et la pousser sur github. Avec l'aide de &lt;a href="http://stackoverflow.com/questions/4752387/github-pushing-a-local-branch"&gt;StackOverflow&lt;/a&gt;, voilà ce que je fis:&lt;br /&gt;&lt;br /&gt;Tout d'abord, créer une nouvelle branche à l'aide de la commande "checkout":&lt;br /&gt;&lt;br /&gt;# git checkout -b gallery&lt;br /&gt;&lt;br /&gt;Git me confirme que mes changements sont maintenant bien situés sur la branche, et m'indique "Switched to a new branch 'gallery'". &lt;br /&gt;&lt;br /&gt;# git branch&lt;br /&gt;&lt;br /&gt;* gallery&lt;br /&gt;  master&lt;br /&gt;&lt;br /&gt;C'est bien la confirmation que j'ai maintenant deux branches, et que ma branche courante est gallery. Ouf!&lt;br /&gt;&lt;br /&gt;# git commit&lt;br /&gt;&lt;br /&gt;# git push origin gallery&lt;br /&gt;&lt;br /&gt;Voilà, ma branche est partie sur github. Je vérifie sur le &lt;a href="https://github.com/smallduckinette/medoc/network"&gt;graphe des branches&lt;/a&gt; que tout est bien comme je m'y attendais.&lt;br /&gt;&lt;br /&gt;Je vais finir par y comprendre quelque chose.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-7689081893326039036?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/7689081893326039036/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=7689081893326039036' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7689081893326039036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7689081893326039036'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/11/github-ca-vient-doucement.html' title='Github - Ça vient doucement...'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-2375194898833138675</id><published>2011-11-22T23:16:00.002+01:00</published><updated>2011-11-22T23:36:46.486+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Benchmark</title><content type='html'>Je testais aujourd'hui les performances d'un nouveau bout de code pour faire de la sérialisation, templaté de partout, le comparant à du vieux code moins générique, mais réputé rapide.&lt;br /&gt;&lt;br /&gt;Et je ne comprenais pas pourquoi mon nouveau code, sur un bout tout simple, le calcul de la taille du buffer nécessaire à la sérialisation d'un vecteur de chaînes de caractères, était plus lent. Pour un vecteur de 10000 chaînes, mon code tournait à 19µs, et l'autre à 14µs.&lt;br /&gt;&lt;br /&gt;L'algorithme était pourtant tout bête: on prend 4 pour contenir la taille du vecteur, puis on ajoute pour chaque chaîne 4, pour la longueur de la chaine, puis la longueur de la chaîne elle-même. En pseudo-code, pour un vecteur v: 4 + (for each c in v : 4 + length(c)).&lt;br /&gt;&lt;br /&gt;Je tente de remplacer mes itérateurs par des entiers et des index, j'enlève et remets les templates, je vérifie bien que le compilo inline tout... Toujours la différence.&lt;br /&gt;&lt;br /&gt;Finalement, c'était tout bête. Une telle différence vient rarement des micro-optimisations du code, et bien plus souvent d'un algorithme suboptimal. Le vieux code calculait la longueur de cette manière: 4 + 4 * length(v) + (for each c in v : length(c)). Ce qui sauvait 10000 additions contre une simple multiplication, et me coûtait les 4µs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-2375194898833138675?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/2375194898833138675/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=2375194898833138675' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2375194898833138675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2375194898833138675'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/11/benchmark.html' title='Benchmark'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-7380861337739598410</id><published>2011-11-19T18:20:00.004+01:00</published><updated>2011-11-19T18:31:30.390+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='client'/><title type='text'>wxWidgets - Un OK plus standard</title><content type='html'>Avant:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-lwOnxlZFbx8/TsfmMrkYVvI/AAAAAAAAEfQ/eaxwFipL5Hs/s1600/wxwidgets_nonstd.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 198px;" src="http://4.bp.blogspot.com/-lwOnxlZFbx8/TsfmMrkYVvI/AAAAAAAAEfQ/eaxwFipL5Hs/s320/wxwidgets_nonstd.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5676758960851932914" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Après:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-3Bo-pV0uyzc/TsfmM4WZ5_I/AAAAAAAAEfY/4GmpFAB16RI/s1600/wxwidgets_std.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 198px;" src="http://2.bp.blogspot.com/-3Bo-pV0uyzc/TsfmM4WZ5_I/AAAAAAAAEfY/4GmpFAB16RI/s320/wxwidgets_std.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5676758964282976242" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;La méthode wxDialog::CreateStdDialogButtonSizer créé automatiquement les boutons standards pour la plateforme, en termes de disposition (à droite, OK puis Cancel pour Windows, Cancel puis OK pour Apple et GTK, avec le texte et les icônes...). La méthode renvoie un sizer, qu'il est possible d'ajouter directement au sizer principal de la boite de dialogue.&lt;br /&gt;&lt;br /&gt;C'est y pas plus joli comme ça?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-7380861337739598410?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/7380861337739598410/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=7380861337739598410' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7380861337739598410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7380861337739598410'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/11/wxwidgets-un-ok-plus-standard.html' title='wxWidgets - Un OK plus standard'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-lwOnxlZFbx8/TsfmMrkYVvI/AAAAAAAAEfQ/eaxwFipL5Hs/s72-c/wxwidgets_nonstd.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-7163537797611401070</id><published>2011-11-13T23:00:00.001+01:00</published><updated>2011-11-13T23:02:19.643+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='médoc'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>OCaml détecté</title><content type='html'>Yay, Github a manifestement refait tourner les statistiques, et &lt;a href="https://github.com/smallduckinette/medoc/graphs/languages"&gt;détecte bien maintenant que Médoc est fait à 45% d'OCaml&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-7163537797611401070?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/7163537797611401070/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=7163537797611401070' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7163537797611401070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7163537797611401070'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/11/ocaml-detecte.html' title='OCaml détecté'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-5788481383479749466</id><published>2011-11-13T19:42:00.002+01:00</published><updated>2011-11-13T19:55:57.740+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='client'/><title type='text'>Écrire son propre wxImageHandler - Lire des PDF</title><content type='html'>La bibliothèque wxWidgets fait reposer son système de chargement d'images sur la classe wxImageHandler. L'idée est d'en dériver, et de fournir l'implémentation pour lire son type d'image particulier. Une fois ajouté au framework, l'application peut lire le nouveau type d'image de manière transparente.&lt;br /&gt;&lt;br /&gt;Voici un wxImageHandler très basique pour afficher, sous forme d'image, des fichiers PDF, en utilisant les routines de la bibliothèque ImageMagick.&lt;br /&gt;&lt;br /&gt;Tout d'abord, le fichier d'en tête, tout simple: l'on dérive de wxImageHandler, et l'on implémente les méthodes "GetImageCount", "LoadFile", "SaveFile", et "DoCanRead".&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;wx/wx.h&amp;gt;&lt;br /&gt;&lt;br /&gt;class PdfImageHandler : public wxImageHandler&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  PdfImageHandler();&lt;br /&gt;&lt;br /&gt;  virtual int GetImageCount(wxInputStream &amp;amp; stream);&lt;br /&gt;  virtual bool LoadFile(wxImage * image,&lt;br /&gt;                        wxInputStream &amp;amp; stream, &lt;br /&gt;                        bool verbose=true, &lt;br /&gt;                        int index=-1);&lt;br /&gt;  virtual bool SaveFile(wxImage * image, &lt;br /&gt;                        wxOutputStream &amp;amp; stream, &lt;br /&gt;                        bool verbose=true);&lt;br /&gt;  &lt;br /&gt;protected:&lt;br /&gt;  bool DoCanRead(wxInputStream &amp;amp; stream);&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;À l'implémentation, l'on utilise l'API Magick++, et un peu de MagickCore, pour lire le fichier PDF et le renvoyer sous forme d'image.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include "PdfImageHandler.h"&lt;br /&gt;&lt;br /&gt;#include &amp;lt;Magick++.h&amp;gt; &lt;br /&gt;#include &amp;lt;wx/mstream.h&amp;gt;&lt;br /&gt;&lt;br /&gt;namespace&lt;br /&gt;{&lt;br /&gt;  std::list&amp;lt;Magick::Image&amp;gt; loadImages(wxInputStream &amp;amp; stream)&lt;br /&gt;  {&lt;br /&gt;    wxFileOffset offset = stream.TellI();&lt;br /&gt;    wxMemoryOutputStream buffer;&lt;br /&gt;    stream.Read(buffer);&lt;br /&gt;    stream.SeekI(offset);&lt;br /&gt;    &lt;br /&gt;    Magick::Blob blob  &lt;br /&gt;      (buffer.GetOutputStreamBuffer()-&amp;gt;GetBufferStart(),&lt;br /&gt;       buffer.GetOutputStreamBuffer()-&amp;gt;GetBufferSize());&lt;br /&gt;    &lt;br /&gt;    std::list&amp;lt;Magick::Image&amp;gt; images;&lt;br /&gt;    Magick::readImages(&amp;amp;images, blob);&lt;br /&gt;    return images;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;PdfImageHandler::PdfImageHandler()&lt;br /&gt;{&lt;br /&gt;  SetName(_("PdfImageHanlder"));&lt;br /&gt;  SetExtension(_("pdf"));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int PdfImageHandler::GetImageCount(wxInputStream &amp;amp; stream)&lt;br /&gt;{&lt;br /&gt;  return loadImages(stream).size();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;bool PdfImageHandler::LoadFile(wxImage * image, &lt;br /&gt;                               wxInputStream &amp;amp; stream, &lt;br /&gt;                               bool verbose, &lt;br /&gt;                               int index)&lt;br /&gt;{&lt;br /&gt;  std::list&amp;lt;Magick::Image&amp;gt; images = loadImages(stream);&lt;br /&gt;  std::list&amp;lt;Magick::Image&amp;gt;::iterator it = images.begin();&lt;br /&gt;  if(index != -1)&lt;br /&gt;  {&lt;br /&gt;    std::advance(it, index);&lt;br /&gt;  }&lt;br /&gt;  if(it != images.end())&lt;br /&gt;  {&lt;br /&gt;    Magick::Image &amp;amp; page = *it;&lt;br /&gt;    Magick::Blob blob;&lt;br /&gt;    page.write(&amp;amp;blob);&lt;br /&gt;    wxMemoryInputStream input(blob.data(), blob.length());&lt;br /&gt;    *image = wxImage(input);&lt;br /&gt;    return true;&lt;br /&gt;  }&lt;br /&gt;  else&lt;br /&gt;  {&lt;br /&gt;    return false;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;bool PdfImageHandler::SaveFile(wxImage * image, &lt;br /&gt;                               wxOutputStream &amp;amp; stream, &lt;br /&gt;                               bool verbose)&lt;br /&gt;{&lt;br /&gt;  return false;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;bool PdfImageHandler::DoCanRead(wxInputStream &amp;amp; stream)&lt;br /&gt;{&lt;br /&gt;  unsigned char hdr[4];&lt;br /&gt;  if(!stream.Read(hdr, WXSIZEOF(hdr)))&lt;br /&gt;  {&lt;br /&gt;    return false;&lt;br /&gt;  }&lt;br /&gt;  else&lt;br /&gt;  {&lt;br /&gt;    return memcmp(hdr, "%PDF", WXSIZEOF(hdr)) == 0;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;La routine est malheureusement très inefficace: l'on se retrouvera à charger l'ensemble du PDF pour retourner le nombre de pages, puis recharger l'ensemble du PDF pour retourner chaque page. ImageMagick propose des routines permettant de "pinger" une image, c'est à dire d'en charger les propriétés sans les données. Pas sûr que le chargement de fichiers PDF, qui passe par GhostScript, permette ce genre d'astuce pour ne charger que l'image courante.&lt;br /&gt;&lt;br /&gt;Mais si ce n'est pas rapide, au moins, ça marche! Une fois le handler ajouté, via une ligne du type &lt;pre&gt;wxImage::AddHandler(new PdfImageHandler);&lt;/pre&gt; il devient possible de charger directement un fichier PDF dans une wxImage. L'on pourra utiliser wxImage::GetImageCount et le paramètre d'index du constructeur pour aller chercher chaque page individuellement.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-5788481383479749466?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/5788481383479749466/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=5788481383479749466' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5788481383479749466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5788481383479749466'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/11/ecrire-son-propre-wximagehandler-lire.html' title='Écrire son propre wxImageHandler - Lire des PDF'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-2523933563458519738</id><published>2011-11-07T23:22:00.003+01:00</published><updated>2011-11-07T23:32:42.120+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><category scheme='http://www.blogger.com/atom/ns#' term='projet'/><title type='text'>Je commence à apprécier Github</title><content type='html'>Ce site est un vrai petit bijou. Je découvre leur système de tickets, qui permet de lever des bugs ou des feature requests, de les assigner à un développeur et à une release et de les tagger. Ensuite, lorsque l'on corrige le ticket n, il suffit d'avoir "fix #n", "fixes #n", "close #n" ou "closes #n" dans le message de commit. Par exemple, mon dernier commit: "Added possibility to clear all loaded images. Fixes #1." ferme automatiquement le &lt;a href="https://github.com/smallduckinette/medoc/issues/1"&gt;ticket correspondant&lt;/a&gt;, en y incluant le commentaire et un lien vers le commit, et ceci, pratiquement immédiatement après le push.&lt;br /&gt;&lt;br /&gt;Par contre, étrangement, les statistiques en termes de langages utilisés ont l'air un poil cassé: j'ai commité ce week-end un millier de lignes d'OCaml et un peu de SQL, mais Github indique obstinément 100% de C++.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-2523933563458519738?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/2523933563458519738/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=2523933563458519738' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2523933563458519738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2523933563458519738'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/11/je-commence-apprecier-github.html' title='Je commence à apprécier Github'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4999089314799936559</id><published>2011-11-02T22:45:00.005+01:00</published><updated>2011-11-02T23:03:45.363+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='médoc'/><title type='text'>Médoc - C'est utilisable</title><content type='html'>Mon dernier commit complète la phase initiale du client lourd Médoc: il est maintenant possible d'importer un document via le scanner, puis de le sauver dans la base de données. Il aura fallu ajouter quelques boites de dialogues pour entrer la configuration de la base, et pour définir les détails du document.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-PTR9qGtkgE8/TrG7gK5ysjI/AAAAAAAAEew/vay55cWFnNQ/s1600/medoc-db2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 238px;" src="http://2.bp.blogspot.com/-PTR9qGtkgE8/TrG7gK5ysjI/AAAAAAAAEew/vay55cWFnNQ/s320/medoc-db2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5670519567193125426" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-h4Mn6TvNSW8/TrG7gL2Z3MI/AAAAAAAAEeg/5n5kqXQsBZs/s1600/medoc-db.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 238px;" src="http://1.bp.blogspot.com/-h4Mn6TvNSW8/TrG7gL2Z3MI/AAAAAAAAEeg/5n5kqXQsBZs/s320/medoc-db.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5670519567447350466" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Il va falloir travailler sur bon nombre de détails pour rendre le client vraiment efficace, comme par exemple pouvoir effacer ou réordonner les pages, ou sauver les paramètres de la session précédente pour ne pas avoir à tout redéfinir à chaque fois.&lt;br /&gt;&lt;br /&gt;Le problème principal, pour l'instant, est d'arriver à trouver enfin la configuration du scanner qui fonctionne correctement. Pour mon scanner HP, SANE me sort la liste d'options suivante:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-xMYcOuy3Ics/TrG8ffgplOI/AAAAAAAAEe4/FrFtP5OX-sM/s1600/medoc-hp-sane-options.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 295px;" src="http://2.bp.blogspot.com/-xMYcOuy3Ics/TrG8ffgplOI/AAAAAAAAEe4/FrFtP5OX-sM/s320/medoc-hp-sane-options.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5670520655056573666" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Déjà, pour "Length measurement", il faut absolument changer l'option de "Padded" à "Approximate", sinon le scanner ajoute de lui même une horrible bande blanche en dessus des documents. Ensuite, vient le souci du batch: mon scanner peut scanner une pile de documents d'un coup, dans lequel cas il faut à la fin de chaque page boucler et tester si le scanner est prêt. Si l'on a bien mis l'option "Batch", le scanner répond après la dernière page qu'il n'y a plus de documents, et tout s'arrête. Tout va bien. Si l'on oublie l'option "Batch", par contre, le scanner tourne indéfiniment.&lt;br /&gt;&lt;br /&gt;Pire, lors du scan à plat: dans ce cas, le scanner indique toujours un document comme étant disponible. Dans ce cas, il ne faut simplement pas boucler. Il semblerait donc que je sois obligé de demander à l'utilisateur son intention. J'aurais préféré que le scan soit plus intelligent, et me retourne une condition d'arrêt dans tous les cas. &lt;br /&gt;&lt;br /&gt;Bien entendu, ce n'est valide que pour mon modèle de scanner. À partir de là, si quiconque veut tenter l'aventure, hic sunt dracones.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4999089314799936559?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4999089314799936559/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4999089314799936559' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4999089314799936559'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4999089314799936559'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/11/medoc-cest-utilisable.html' title='Médoc - C&apos;est utilisable'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-PTR9qGtkgE8/TrG7gK5ysjI/AAAAAAAAEew/vay55cWFnNQ/s72-c/medoc-db2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-6787588175613723752</id><published>2011-10-31T23:58:00.003+01:00</published><updated>2011-11-01T00:23:43.235+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='postgres'/><title type='text'>Mélanger pqxx et wxWidgets</title><content type='html'>Une part non négligeable du boulot de développeur est de convertir des données d'un format vers un autre pour faire causer deux composants séparés.&lt;br /&gt;&lt;br /&gt;Alors, pour une fois que c'est simple, l'on ne va pas bouder notre plaisir. C'est que le concepteur de libpqxx a eu la bonne idée de fournir des type traits pour passer ses propres types à la base de données pour les requêtes préparées.&lt;br /&gt;&lt;br /&gt;Si l'on veut donc pouvoir sauver des chaînes de caractères wxWidgets (wxString) ou des dates (wxDateTime), il suffit d'implémenter le trait qui va bien. Cela ressemble à ça:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;namespace pqxx&lt;br /&gt;{&lt;br /&gt;  template&amp;lt;&amp;gt; struct PQXX_LIBEXPORT string_traits&amp;lt;wxString&amp;gt;&lt;br /&gt;  {&lt;br /&gt;    static const char * name() { return "wxString"; }&lt;br /&gt;    static bool has_null() { return false; }&lt;br /&gt;    static bool is_null(const wxString &amp;amp;) { return false; }&lt;br /&gt;    static wxString null() &lt;br /&gt;    { internal::throw_null_conversion(name()); return wxString(); }&lt;br /&gt;    static void from_string(const char Str[], wxString &amp;amp; Obj) &lt;br /&gt;    { Obj = wxString(Str, wxConvUTF8); }&lt;br /&gt;    static PGSTD::string to_string(const wxString &amp;amp; Obj) &lt;br /&gt;    { return std::string(Obj.mb_str(wxConvUTF8)); }&lt;br /&gt;  };&lt;br /&gt;  &lt;br /&gt;  template&amp;lt;&amp;gt; struct PQXX_LIBEXPORT string_traits&amp;lt;wxDateTime&amp;gt;&lt;br /&gt;  {&lt;br /&gt;    static const char * name() { return "wxDateTime"; }&lt;br /&gt;    static bool has_null() { return false; }&lt;br /&gt;    static bool is_null(const wxDateTime &amp;amp;) &lt;br /&gt;    { return false; }&lt;br /&gt;    static wxDateTime null() &lt;br /&gt;    { internal::throw_null_conversion(name()); return wxDateTime(); }&lt;br /&gt;    static void from_string(const char Str[], wxDateTime &amp;amp; Obj) &lt;br /&gt;    { Obj.ParseDateTime(wxString(Str, wxConvUTF8)); }&lt;br /&gt;    static PGSTD::string to_string(const wxDateTime &amp;amp; Obj) &lt;br /&gt;    { return std::string(Obj.Format().mb_str(wxConvUTF8)); }&lt;br /&gt;  };&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;L'on indique simplement comment convertir une PGSTD::string (qui est en fait une bête std::string) dans le type de travail, et basta, avec ça, les appels du type &lt;pre&gt;T.prepared("statement")(wxString1)(wxString2)(wxDateTime1).exec();&lt;/pre&gt; passent comme une lettre à la poste.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-6787588175613723752?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/6787588175613723752/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=6787588175613723752' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6787588175613723752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6787588175613723752'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/10/melanger-pqxx-et-wxwidgets.html' title='Mélanger pqxx et wxWidgets'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-1902559703907627349</id><published>2011-10-30T15:52:00.002+01:00</published><updated>2011-10-30T16:01:30.055+01:00</updated><title type='text'>La punchcard de github</title><content type='html'>J'aime bien le graphique "punchcard" de github. Pour &lt;a href="https://github.com/smallduckinette/medoc/graphs/punch_card"&gt;Médoc&lt;/a&gt;, par exemple, l'on voit bien que je ne suis pas un matinal, et que je code le week-end et en soirée (forcément, le reste du temps, je code pour manger). Plus étrange, il semble que je sois plus productif en début de semaine qu'en fin.&lt;br /&gt;&lt;br /&gt;L'on pourra comparer (façon de parler...) avec la punchcard du &lt;a href="https://github.com/torvalds/linux/graphs/punch_card"&gt;noyau linux&lt;/a&gt;, où les développeurs travaillent principalement la semaine entre 9h et 17h.&lt;br /&gt;&lt;br /&gt;Je suis plutôt satisfait de GitHub, non que j'utilise plus d'un pouillème de ses fonctionnalités. Le push est très rapide, le site réactif, et les stats rigolotes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-1902559703907627349?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/1902559703907627349/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=1902559703907627349' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1902559703907627349'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1902559703907627349'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/10/la-punchcard-de-github.html' title='La punchcard de github'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-2608491270033534724</id><published>2011-10-22T00:39:00.002+02:00</published><updated>2011-10-22T00:47:42.165+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>std::lower_bound</title><content type='html'>Imaginons que l'on veuille enregistrer une série de segments [a; b[, et à partir d'un point donné, rapidement retrouver le segment auquel il appartient. Typiquement: sachant que chaque événement court entre deux dates, pour une date donnée, trouver de quel événement il s'agit.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Comment donc placer ses segments dans une structure pour s'y retrouver simplement et efficacement?&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Et comment gérer plusieurs segments qui se chevauchent?&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-2608491270033534724?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/2608491270033534724/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=2608491270033534724' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2608491270033534724'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2608491270033534724'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/10/stdlowerbound.html' title='std::lower_bound'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-1869839914832191453</id><published>2011-10-18T00:06:00.002+02:00</published><updated>2011-10-18T00:22:07.933+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='médoc'/><title type='text'>Médoc - Dernières nouvelles</title><content type='html'>Belles améliorations ce week-end de la partie import. J'ai découvert que je m'étais planté sur le nombre d'options disponibles, et qu'il y en avait de fait bien plus. Deux options en particulier:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;La &lt;i&gt;length-measurement&lt;/i&gt;: mon scanner HP considère (et renvoie via l'API) que la longueur de la page est environ deux fois plus grande que la largeur. Par défaut (l'option &lt;i&gt;Padded&lt;/i&gt;), il ajoute donc une grande bande blanche en dessous de la page standard 210x297. Mais en mode &lt;i&gt;Approximate&lt;/i&gt;, il me renvoie un signal de fin de données lorsqu'il arrive à la vraie fin de la page.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Le &lt;i&gt;batch-scan&lt;/i&gt;: sans cette option, le scan à plat fonctionne normalement, mais le scan déroulant pour plusieurs documents s'y perd, et après la dernière page se met à scanner des pages vides jusqu'à ce que l'on termine le job manuellement. Avec l'option, il s'arrête à la dernière page, mais c'est alors le scan à plat qui refuse d'avancer! Il n'est pas sûr que j'arrive à trouver la combinaison d'options qui marche tout le temps, donc il va peut-être falloir que l'utilisateur indique s'il compte scanner une seule ou plusieurs pages.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Ceci dit, et pour peu que l'on fasse attention aux options, l'import est parfaitement fonctionnel. Quelques options supplémentaires, comme le réarrangement des pages, ou la rotation d'une image, seront utiles, bien sûr. Mais maintenant, le minimum nécessaire pour rendre l'outil utile est d'implémenter les fonctions d'export, vers une base de données Médoc, ou vers un pdf.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-1869839914832191453?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/1869839914832191453/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=1869839914832191453' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1869839914832191453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1869839914832191453'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/10/medoc-dernieres-nouvelles.html' title='Médoc - Dernières nouvelles'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-848704500662171470</id><published>2011-10-13T00:10:00.002+02:00</published><updated>2011-10-13T00:27:31.386+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Et Jira se facebookise</title><content type='html'>Décidément, c'est la saison.&lt;br /&gt;&lt;br /&gt;Atlassian Software est une petite boite australienne qui a fait son trou dans les outils collaboratifs, et notamment &lt;a href="http://www.atlassian.com/software/jira/"&gt;Jira&lt;/a&gt;, qui est un outil web de suivi de bugs, plutôt bien fait d'ailleurs.&lt;br /&gt;&lt;br /&gt;Nous avons bondi de la version 3.7 à la version 4.4, et là, c'est le drame. Cette transition corrige quelques défauts qui étaient certes ennuyeux, mais mineurs, mais surtout propulse le système de suivi à l'ère Facebook. Fausse bonne idée? Probablement.&lt;br /&gt;&lt;br /&gt;Flux RSS de partout, avatars personnalisés, aucun doute, c'est du Web 2.0.&lt;br /&gt;&lt;br /&gt;Que vous aimiez Ajax ou pas, vous aller en manger. L'ensemble de la plateforme, et plus particulièrement l'écran principal (le "dashboard") est maintenant asynchrone. Au démarrage, plutôt que de voir ses filtres habituels (typiquement, la liste des bugs assignés), l'on a droit à des panneaux vides avec des petites barres de progression type enseigne de barbier, pour finalement afficher quelque chose d'intéressant plusieurs secondes plus tard. C'est la même chose pour ajouter un commentaire à un ticket, ou enregistrer son temps de travail. Le javascript est présent en doses pour rhinocéros, chaque menu est dynamique, chaque panneau ou section du bug peut se replier ou se déplier, et les différentes sections de la page peuvent être réarrangées par glisser déposer.&lt;br /&gt;&lt;br /&gt;Le résultat, c'est un site beaucoup plus lent sous Firefox, et à peu près inutilisable sous Internet Explorer 8.&lt;br /&gt;&lt;br /&gt;Mais c'est joli, ce qui a probablement été suffisant pour convaincre le manager kivabien de procéder à la mise à jour.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-848704500662171470?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/848704500662171470/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=848704500662171470' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/848704500662171470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/848704500662171470'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/10/et-jira-se-facebookise.html' title='Et Jira se facebookise'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-7439255352789239429</id><published>2011-10-12T23:00:00.003+02:00</published><updated>2011-10-12T23:44:36.786+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Project Euler fait peau neuve</title><content type='html'>Le site de &lt;a href="http://projecteuler.net/"&gt;Project Euler&lt;/a&gt;, le site de problèmes informatico-mathématiques, faisait un peu figure de dinosaure du Web. Eh bien, c'est fini, à la mi-Septembre le site web a été refondu en une version bien plus Web 2.0. &lt;br /&gt;&lt;br /&gt;Le style est plus aéré, les statistiques ont été légèrement modifiés, et il y a maintenant un système de médailles basé sur les problèmes résolus, comme par exemple avoir résolu 50 problèmes liés aux nombres premiers, ou d'avoir résolu 12 problèmes au dessus du centième. L'on notera également un système de suivi permet de tenir ses amis à l’œil.&lt;br /&gt;&lt;br /&gt;Les performances semblent avoir décru, et le site parait vraiment ramer. C'était parfois le cas avec l'ancien, donc difficile de savoir si c'est dû à une plus grande popularité, ou que le nouveau site cause une charge plus importante sur leurs serveurs. Ce n'est de toutes façons pas très gênant, ce n'est pas comme si je résolvais les problèmes si vite que leur chargement devienne fastidieux.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-7439255352789239429?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/7439255352789239429/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=7439255352789239429' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7439255352789239429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7439255352789239429'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/10/project-euler-fait-peau-neuve.html' title='Project Euler fait peau neuve'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-3550387498411441846</id><published>2011-10-08T19:32:00.005+02:00</published><updated>2011-10-08T19:49:28.224+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='médoc'/><title type='text'>Médoc et wxWidgets</title><content type='html'>Il est tentant de vouloir adapter les bibliothèques, au passé souvent chargé, aux concepts et techniques du C++ moderne. Et pourtant, principalement pour les projets assez indépendants, il vaut mieux s'asseoir un peu sur ses principes, et utiliser la bibliothèque de la manière qu'elle a été pensée.&lt;br /&gt;&lt;br /&gt;Prenons la bonne vieille wxWidgets, avec laquelle je suis en train de créer mon client lourd Médoc. Elle utilise sa propre classe de chaines de caractères, afin de supporter plusieurs types d'encodage, ses propres tableaux dynamiques en place du bon vieux std::vector, et utilise des macros un peu partout.&lt;br /&gt;&lt;br /&gt;J'ai tendance à importer immédiatement quelques utilitaires de base que je garde dans un coin, du genre conversion entre wxString et std::string. Mais pour Médoc, je crois bien pouvoir m'en passer: mes entrées comme mes sorties passant soit par wxWidgets elle-même, soit par des bibliothèques en C pur, il est plus cohérent de simplement utiliser des wxString partout.&lt;br /&gt;&lt;br /&gt;Voilà donc, en 300 lignes, un programme qui permet de charger des images dans une liste, et de les afficher en cliquant dessus:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-KOYH05xik_Q/TpCMwW_Oc-I/AAAAAAAAEeY/2EmLdJB18cg/s1600/medoc.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 215px;" src="http://2.bp.blogspot.com/-KOYH05xik_Q/TpCMwW_Oc-I/AAAAAAAAEeY/2EmLdJB18cg/s320/medoc.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5661179494037091298" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;C'est maintenant que ça se gâte: remplacer la liste d'images par une vraie galerie, permettant d'afficher une miniature de l'image, et d'en changer l'ordre par du glisser-déposer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-3550387498411441846?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/3550387498411441846/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=3550387498411441846' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3550387498411441846'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3550387498411441846'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/10/medoc-et-wxwidgets.html' title='Médoc et wxWidgets'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-KOYH05xik_Q/TpCMwW_Oc-I/AAAAAAAAEeY/2EmLdJB18cg/s72-c/medoc.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-2788852056407662926</id><published>2011-10-03T23:46:00.003+02:00</published><updated>2011-10-04T00:02:18.020+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>4 ans...</title><content type='html'>Je postais mon premier message sur ce blog le 1er Octobre 2007. 4 ans et 324 messages plus tard, les thématiques n'ont pas beaucoup changé (C++, OCaml, Postgresql, jeux vidéos). On a causé C++0x, on a causé Blender, on a même causé Emacs et astuces Debian.&lt;br /&gt;&lt;br /&gt;Merci à mes lecteurs de chez l'université de Metz, de chez LinuxFR, de chez le "site du zéro", de chez Identi.ca (des Adaistes...) et de partout ailleurs de leur assiduité. Je leur souhaite de vouloir me lire encore pendant de nombreuses années, parce que j'ai bien des choses à dire!&lt;br /&gt;&lt;br /&gt;Entre le C++0x qui va commencer à arriver en production dans divers systèmes à travers le monde, des nouveautés attendues dans Postgresql (je pense notamment aux ranges, qui je l'espère permettront de simplifier les bases de données historiques), les nombreux jeux que j'attends de pied ferme (Skyrim!), et diverses bêtises à partager, nous en avons pour un petit bout de temps.&lt;br /&gt;&lt;br /&gt;@+!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-2788852056407662926?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/2788852056407662926/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=2788852056407662926' title='2 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2788852056407662926'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2788852056407662926'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/10/4-ans.html' title='4 ans...'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4192394113389491779</id><published>2011-09-30T00:39:00.002+02:00</published><updated>2011-09-30T00:40:21.414+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='médoc'/><category scheme='http://www.blogger.com/atom/ns#' term='projet'/><title type='text'>Un client lourd Médoc</title><content type='html'>Mon projet de documentation &lt;a href="http://aubedesheros.blogspot.com/2009/10/medoc-stable.html"&gt;Médoc&lt;/a&gt; continue de fonctionner impeccablement, du moins du côté de la base de données et du client Web. Par contre, le client lourd en OCaml et LablGTK, chargé de charger les documents dans la base à partir du scanner ou d'un fichier, commence à tomber en ruines.&lt;br /&gt;&lt;br /&gt;Pas très ergonomique d'une part, et pas très intégré d'autre part (la plupart des commandes, telles le chargement de fichier ou le scan en lui-même, sont faites à partir de lignes de commandes lancées par le programme). Je me suis donc mis à écrire un client lourd en C++ avec WxWidgets qui soit un peu plus pratique à utiliser. La libsane se chargera de piloter le scanner, libmagick++ sait apparemment transformer un pdf en image, et la libharu sait transformer une image en pdf.&lt;br /&gt;&lt;br /&gt;Y'a plus qu'à coller les morceaux.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4192394113389491779?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4192394113389491779/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4192394113389491779' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4192394113389491779'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4192394113389491779'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/09/un-client-lourd-medoc.html' title='Un client lourd Médoc'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-318825101040227973</id><published>2011-09-28T22:48:00.005+02:00</published><updated>2011-09-28T23:18:10.932+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='projet'/><title type='text'>Courir après sa base de données</title><content type='html'>&lt;a href="http://www.life-is-an-ultramarathon.org"&gt;Julien&lt;/a&gt; me parlait de systèmes de suivi de courses type marathon ou trail à base de RFID, et il n'en a pas fallu plus pour enflammer mon imagination. Je pensais à ce à quoi ressemblerait un schéma de base de données enregistrant le passage des coureurs à des points donnés, afin de permettre le suivi par les commissaires de courses, le public, et la publication des résultats et des statistiques pour les coureurs. Et on dirait bien qu'un tel système présente une sacrée dose de défis.&lt;br /&gt;&lt;br /&gt;L'on s'intéressera plutôt aux courses de type ultramarathon ou trail, sur chemins ou en pleine nature, où les coureurs doivent s'enregistrer auprès des commissaires de courses à des points de passages déterminés. Le coureur passe donc son RFID au dessus de l'appareil du commissaire de course, et repart.&lt;br /&gt;&lt;br /&gt;Voyons donc ce schéma. Les faits sont assez simples: une table contenant chaque détection d'un coureur à un point de passage. Mais qu'est-ce qu'un coureur, et qu'est-ce que c'est qu'un point de passage? Redéfinissons: notre table contient chaque détection d'un RFID par un appareil. Et il ne doit pas être possible de modifier ou d'enlever une ligne: une détection est une détection. Elle s'est effectuée à une certaine heure déterminée par l'appareil, et reçue à une autre heure (parfois beaucoup plus tard s'il y a des soucis de connectivité) par la base de données.&lt;br /&gt;&lt;br /&gt;(device_id, rfid, device_timestamp, local_timestamp)&lt;br /&gt;&lt;br /&gt;L'on pensera bien sûr aux pannes: si un rfid ou un appareil ne fonctionne plus, le commissaire pourrait se retrouver forcé d'enregistrer les coureurs manuellement via un autre type d'identification, comme un dossard.&lt;br /&gt;&lt;br /&gt;(marshal_id, runner_id, marshal_timestamp, local_timestamp)&lt;br /&gt;&lt;br /&gt;Ce sont les faits: irréfutables.&lt;br /&gt;&lt;br /&gt;Maintenant, tout le problème est de rajouter les tables qui permettront d'associer les appareils aux points de passages, et les RFID aux coureurs.&lt;br /&gt;&lt;br /&gt;- Un coureur découvre en milieu de course que son RFID est défectueux, et un commissaire de course lui en fournit un autre&lt;br /&gt;- N'ayant cependant pas rendu son premier RFID, qui s'est tout à coup mis à remarcher, il passe parfois l'un, parfois l'autre aux points de passages&lt;br /&gt;- Deux coureurs échangent un sac, et oublient que leur RFID était dedans&lt;br /&gt;&lt;br /&gt;- Un commissaire change de point de passage, et garde avec lui son appareil&lt;br /&gt;- Les commissaires découvrent que l'appareil pour la détection à l'arrivée est en panne, et décident de rapatrier un autre appareil pour l'arrivée, où une détection précise est plus importante&lt;br /&gt;&lt;br /&gt;Toute la difficulté est donc de maintenir l'état le plus fréquent (un coureur ayant correctement été enregistré par son RFID par les bon appareils aux bons endroits), tout en permettant un réglage fin de toutes les petites déviations qui surviennent lorsque la réalité débarque avec ses gros sabots dans la théorie.&lt;br /&gt;&lt;br /&gt;Peut-on rajouter la positien GPS de chaque appareil à chaque enregistrement pour tenter de les associer automatiquement à un point de passage?&lt;br /&gt;Peut-être des tables se basant sur des plages horaires ou géographiques: de telle heure à telle heure, ou de tel point de passage à tel point de passage, le coureur A avait le RFID f, puis il est passé au RFID g?&lt;br /&gt;Ou tout simplement des tables d'override: tel enregistrement doit être ignoré, tel autre doit être considéré comme ayant détecté le RFID g et non f?&lt;br /&gt;&lt;br /&gt;Pas évident.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-318825101040227973?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/318825101040227973/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=318825101040227973' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/318825101040227973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/318825101040227973'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/09/courir-apres-sa-base-de-donnees.html' title='Courir après sa base de données'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-1072140176322590895</id><published>2011-09-27T23:03:00.003+02:00</published><updated>2011-09-27T23:15:05.489+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='projet'/><title type='text'>Github</title><content type='html'>J'ai enfin fait le saut, et me voici sur github. Ayant depuis longtemps eu l'envie de m'essayer à &lt;a href="http://fr.wikipedia.org/wiki/Git"&gt;git&lt;/a&gt;, le logiciel de contrôle de version décentralisé crée par Linus Torvalds, je me suis &lt;a href="https://github.com/smallduckinette/"&gt;ouvert un compte sur github&lt;/a&gt;, et j'ai commencé à commiter.&lt;br /&gt;&lt;br /&gt;Github est particulièrement bien: guidant pas à pas la création du dépôt et la configuration de git, réactif et ergonomique, c'est un petit bijou d'interface. Les performances ont également l'air d'être au rendez-vous. &lt;br /&gt;&lt;br /&gt;Utilisant git de manière mono-utilisateur et mono-branche, mon utilisation est très proche de Subversion (en beaucoup plus rapide cependant, mais les dépôts Subversion de tortue de chez Sourceforge n'aident pas non plus), j'espère cependant au moins m'y initier suffisamment pour ne plus être complètement perdu lorsque certains collègues plus dégourdis jonglent avec git-svn sur les dépôts du boulot.&lt;br /&gt;&lt;br /&gt;Déjà quelques trucs qui m'ont un petit peu bloqué: il n'est pas possible d'avoir des répertoires vides. La solution standard est de créer un .gitignore vide dans le répertoire, et d'ajouter ce fichier. Également, ajouter un répertoire est récursif, ce qui est souvent bien, mais parfois lourd lorsque ce répertoire contient déjà un build, par exemple. Le plus simple est de commencer par nettoyer tous les fichiers non voulus avant d'ajouter.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-1072140176322590895?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/1072140176322590895/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=1072140176322590895' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1072140176322590895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1072140176322590895'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/09/github.html' title='Github'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4587610883140835902</id><published>2011-09-22T00:15:00.002+02:00</published><updated>2011-09-22T00:30:00.985+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Le crible en détail, partie 2</title><content type='html'>Continuons donc à décortiquer le programme.&lt;br /&gt;&lt;br /&gt;La fonction principale de notre crible contient la sous-fonction do_sieve, qui permet une fois de plus de devenir tail recursive, ou à récursion terminale en bon français.&lt;br /&gt;&lt;br /&gt;Elle prend comme paramètres l'entier courant à tester, l'ensemble des multiples des nombres premiers précédents, et la liste courante des nombres premiers. À partir de là, c'est tout bête: l'on retire le premier élément de nos multiples, et on le compare à l'entier à tester. S'ils sont égaux, notre entier courant est un multiple, donc non premier, l'on ré-appelle donc notre fonction récursive avec l'entier suivant. Si ce n'est pas l'entier à tester, on a trouvé un nombre premier! L'on ajoute tous ses multiples à la liste des multiples, l'on rajoute l'entier à la liste de nos nombres premiers, et l'on appelle la fonction récursivement. Et bien sûr, puisqu'il faut bien sortir un jour de la récursion, n'oublions pas notre condition de sortie: lorsque l'entier courant atteint le maximum passé en paramètre de la fonction principale, l'on retourne nos nombres premiers.&lt;br /&gt;&lt;br /&gt;Notez l'optimisation qui consiste à zapper les multiples de 2: l'on démarre à 3, et l'on passe de 2 en 2 pour l'entier courant et pour le calcul des multiples.&lt;br /&gt;&lt;br /&gt;Voici une indication des performances. Loin des meilleurs résultats impératifs, mais tout à fait utilisables.&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;td&gt;Limite&lt;/td&gt;&lt;td&gt;Temps&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;100 000&lt;/td&gt;&lt;td&gt;140ms&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;1 000 000&lt;/td&gt;&lt;td&gt;2.7s&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;10 000 000&lt;/td&gt;&lt;td&gt;41s&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4587610883140835902?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4587610883140835902/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4587610883140835902' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4587610883140835902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4587610883140835902'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/09/le-crible-en-detail-partie-2.html' title='Le crible en détail, partie 2'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-5127157476953619512</id><published>2011-09-17T14:13:00.003+02:00</published><updated>2011-09-17T14:59:01.131+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Le crible en détail, partie 1</title><content type='html'>Mon post précédent était un poil laconique, je vais donc reprendre quelques détails d'implémentation, et en profiter pour vous convaincre que OCaml, ça roxe.&lt;br /&gt;&lt;br /&gt;Les premières lignes sont simplement la définition d'un set sur les entiers. Les sets en OCaml fonctionnent via des modules paramétrés par d'autres modules suivant une certaine signature. L'on créé donc un module définissant un type t et sa comparaison, avec lequel on paramétrise le module Set.Make.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;module OrderedInt =&lt;br /&gt;struct&lt;br /&gt;  type t = int&lt;br /&gt;  let compare = compare&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;module IntSet = Set.Make(OrderedInt)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ceci va donc définir un module tout neuf, que j'appelle IntSet, et qui fournit des fonctions pour travailler sur des sets fonctionnels, c'est à dire sans effets de bords. Ainsi, ajouter un élément au set retourne en fait un nouveau set contenant l'élément. C'est plus efficace qu'il n'y parait, et surtout, cela permet de raisonner à plus haut niveau, d'une manière plus mathématique.&lt;br /&gt;&lt;br /&gt;Ensuite, définissons une fonction qui nous sera utile plus tard, qui retourne une liste d'entiers entre deux entiers définis, avec un pas.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;let seq_step a b t = &lt;br /&gt;  let rec do_seq_step a acc = &lt;br /&gt;    if a &gt; b then &lt;br /&gt;      acc&lt;br /&gt;    else&lt;br /&gt;      do_seq_step (a + t) (a::acc)&lt;br /&gt;  in&lt;br /&gt;  List.rev (do_seq_step a [])&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;La fonction définit une sous-fonction do_seq_step, prenant l'entier courant &lt;i&gt;a&lt;/i&gt;, et la liste d'entiers accumulés jusque là &lt;i&gt;acc&lt;/i&gt;. La récursion est triviale: si mon entier courant a atteint ma borne supérieure, retournons la liste accumulée jusque là. Sinon, appelons récursivement la fonction, avec mon entier courant incrémenté du pas, et ma liste à laquelle j'aurais ajouté mon entier courant.&lt;br /&gt;&lt;br /&gt;Depuis la fonction externe, l'on appelle la sous-fonction en passant la borne inférieure, et une liste vide. Enfin, parce que l'on a accumulé les entiers à l'envers (en partant de 3 de 2 en 2: [3], puis [5; 3], puis [7; 5; 3]...), l'on inverse la liste avec &lt;i&gt;List.rev&lt;/i&gt;. Le résultat:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# seq_step 3 10 2;;&lt;br /&gt;- : int list = [3; 5; 7; 9]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Notez que l'on aurait pu implémenter la fonction d'un coup, de cette façon:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;let rec seq_step2 a b t = &lt;br /&gt;  if a &gt; b then&lt;br /&gt;    []&lt;br /&gt;  else&lt;br /&gt;    a::(seq_step2 (a + t) b t)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Le résultat semble strictement le même, et pourtant:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# seq_step 1 1000000 1;;&lt;br /&gt;- : int list =&lt;br /&gt;[1; 2; 3; 4; 5; 6; 7; 8; 9; ...]&lt;br /&gt;&lt;br /&gt;# seq_step2 1 1000000 1;;&lt;br /&gt;Stack overflow during evaluation (looping recursion?).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;La deuxième version est arrêtée nette par un dépassement de pile. C'est que la première version est une &lt;a href="http://fr.wikipedia.org/wiki/R%C3%A9cursion_terminale"&gt;récursion terminale&lt;/a&gt; (ou tail-recursion en anglais), c'est à dire qu'elle peut être trivialement transformée en une fonction itérative, ce que fait le compilateur. La deuxième, elle, utilise la pile comme accumulateur implicite, et provoque donc un dépassement de pile lorsque le nombre de récursions devient trop important.&lt;br /&gt;&lt;br /&gt;Pour des raisons de performances et d'extensibilité, il est donc recommandé d'implémenter ses fonctions de manière récursive terminale à chaque fois que cela est possible.&lt;br /&gt;&lt;br /&gt;Voilà, suivant l'approche ascendante qui sied bien à OCaml et aux langages fonctionnels, c'est à dire la construction de fonctions de base, puis de fonctions plus haut niveau utilisant ces briques, les utilitaires utilisés pour le crible. Dans la deuxième partie, je reprendrait plus en détails l'algorithme du crible lui-même.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-5127157476953619512?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/5127157476953619512/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=5127157476953619512' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5127157476953619512'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5127157476953619512'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/09/le-crible-en-detail-partie-1.html' title='Le crible en détail, partie 1'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-6857832687574196726</id><published>2011-09-17T00:32:00.003+02:00</published><updated>2011-09-17T00:37:03.539+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Implémentation fonctionnelle d'un crible d'Ératosthène</title><content type='html'>Voilà l'engin:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;module OrderedInt =&lt;br /&gt;struct&lt;br /&gt;  type t = int&lt;br /&gt;  let compare = compare&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;module IntSet = Set.Make(OrderedInt)&lt;br /&gt;&lt;br /&gt;let seq_step a b t = &lt;br /&gt;  let rec do_seq_step a acc = &lt;br /&gt;    if a &gt; b then &lt;br /&gt;      acc&lt;br /&gt;    else&lt;br /&gt;      do_seq_step (a + t) (a::acc)&lt;br /&gt;  in&lt;br /&gt;  List.rev (do_seq_step a [])&lt;br /&gt;&lt;br /&gt;let sieve n = &lt;br /&gt;  let rec do_sieve current multiples primes = &lt;br /&gt;    if current &gt; n then&lt;br /&gt;      primes&lt;br /&gt;    else if IntSet.is_empty multiples || IntSet.min_elt multiples &lt;&gt; current then&lt;br /&gt;      do_sieve &lt;br /&gt;        (current + 2) &lt;br /&gt;        (List.fold_left &lt;br /&gt;           (fun acc e -&gt; IntSet.add e acc)&lt;br /&gt;           multiples&lt;br /&gt;           (seq_step (current * 3) n (current * 2)))&lt;br /&gt;        (current::primes)&lt;br /&gt;    else&lt;br /&gt;      do_sieve (current + 2) (IntSet.remove current multiples) primes&lt;br /&gt;  in&lt;br /&gt;  do_sieve 3 IntSet.empty [2]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Sur ma machine, compilé en natif, trouver les nombres premiers en dessous du million prend 2,7 secondes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-6857832687574196726?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/6857832687574196726/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=6857832687574196726' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6857832687574196726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6857832687574196726'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/09/implementation-fonctionnelle-dun-crible.html' title='Implémentation fonctionnelle d&apos;un crible d&apos;Ératosthène'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-3791508692445919952</id><published>2011-09-14T00:10:00.003+02:00</published><updated>2011-09-14T00:12:34.113+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Un peu de fonctionel</title><content type='html'>Je me suis remis à &lt;a href="http://projecteuler.net"&gt;Project Euler&lt;/a&gt;, et résolu quelques problèmes supplémentaires. Je continue à tenter d'apporter des solutions aussi fonctionnelles pures que possible, ce qui m'a amener à réfléchir à un crible d’Ératosthène fonctionnel pur. Jusqu'ici, j'utilisais les fonctionnalités impératives d'OCaml pour m'en tirer un avec un gros tableau de booléens, mais en fait, si l'on considère un set d'entiers pour les multiplies, il est facile de faire quelque chose de plutôt efficace. Je dois mettre un peu d'ordre dans mon code, et je le posterai ici.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-3791508692445919952?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/3791508692445919952/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=3791508692445919952' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3791508692445919952'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3791508692445919952'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/09/un-peu-de-fonctionel.html' title='Un peu de fonctionel'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-7056665211799492187</id><published>2011-08-31T00:05:00.010+02:00</published><updated>2011-08-31T01:10:29.603+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3d'/><category scheme='http://www.blogger.com/atom/ns#' term='glsl'/><category scheme='http://www.blogger.com/atom/ns#' term='blender'/><title type='text'>Normal maps et Blender 2.5 - Créer un astéroïde</title><content type='html'>Le nouveau Blender ayant changé pas mal de choses, voici la version mise à jour de mon tutoriel sur les normal map, cette foi-ci pour créer un astéroïde. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-JIyfMe4w360/Tl1gGfbpNHI/AAAAAAAAEdY/n9cKWsQdbGM/s1600/01_initial.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 245px;" src="http://2.bp.blogspot.com/-JIyfMe4w360/Tl1gGfbpNHI/AAAAAAAAEdY/n9cKWsQdbGM/s320/01_initial.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5646775172425397362" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Voici l'écran initial de Blender, après être passé à 4 vues (Ctrl-Alt-Q). Virons le cube (sélection avec bouton droit, puis DEL), et ajoutons une icosphère (Shift-A, Mesh =&gt; Icosphere).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-TVDfRunkUc8/Tl1gGfj8TeI/AAAAAAAAEdQ/0mAK6QVJnIU/s1600/02_icosphere.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 245px;" src="http://1.bp.blogspot.com/-TVDfRunkUc8/Tl1gGfj8TeI/AAAAAAAAEdQ/0mAK6QVJnIU/s320/02_icosphere.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5646775172460203490" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;L'on peut maintenant tortiller la sphère dans tous les sens: s + déplacements de souris pour changer sa taille, et s suivi de x, y ou z pour changer la taille dans une dimension seulement. L'on peut sélectionner les points individuellement en passant en mode vertex (TAB), et en sélectionnant les points avec le bouton droit. La touche g permet de déplacer les vertex, et l'on peut une fois de plus restreindre la dimension avec les touches x, y ou z. Formons donc un patatoïde.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-wj2gbaCT_js/Tl1gGP2SbBI/AAAAAAAAEdI/jA008JW8A1E/s1600/03_patatoide.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 245px;" src="http://2.bp.blogspot.com/-wj2gbaCT_js/Tl1gGP2SbBI/AAAAAAAAEdI/jA008JW8A1E/s320/03_patatoide.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5646775168242183186" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Lequel patatoïde nous pouvons maintenant donner une forme plus douce, en y ajoutant le modifier "subdivisions". Dans le menu de droite, allez chercher le tab "Modifiers" (la petite clé à molette), et choisissez "Subdivision Surface". Mettons View et Render à 2. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-qJ3t3IPtfr0/Tl1gF8ibQBI/AAAAAAAAEdA/njZhUr5TWsI/s1600/04_subdivisions.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 245px;" src="http://2.bp.blogspot.com/-qJ3t3IPtfr0/Tl1gF8ibQBI/AAAAAAAAEdA/njZhUr5TWsI/s320/04_subdivisions.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5646775163058602002" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;L'on va ensuite rendre notre patatoïde tout doux: passez en mode vertex (TAB), selectionnez tout (a), et choisissez dans le menu "Mesh Tools" à gauche le shading "Smooth".&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-woR37KzDhJg/Tl1gF8xSn0I/AAAAAAAAEc4/SmcaXLifmkU/s1600/05_smooth.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 245px;" src="http://1.bp.blogspot.com/-woR37KzDhJg/Tl1gF8xSn0I/AAAAAAAAEc4/SmcaXLifmkU/s320/05_smooth.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5646775163120951106" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Allez chercher le tab "Material", et ajoutez un nouveau matériau. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-TWO8ut0hiWo/Tl1goVci9SI/AAAAAAAAEdg/mO8cfrq1DFw/s1600/06_material.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 245px;" src="http://3.bp.blogspot.com/-TWO8ut0hiWo/Tl1goVci9SI/AAAAAAAAEdg/mO8cfrq1DFw/s320/06_material.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5646775753860379938" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Allez ensuite chercher le tab "Texture", et ajoutez une nouvelle texture. Pour donner un aspect rugueux à notre astéroïde, nous allons choisir une texture de type "Cloud", choisir un "noise" à "Hard", et changer son influence en désactivant "Colo" (pour couleur) et en activant "Nor" pour normales.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-pvax7EAMNAc/Tl1goVLI9KI/AAAAAAAAEdo/-wgWz6n2K7I/s1600/07_texture.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 245px;" src="http://1.bp.blogspot.com/-pvax7EAMNAc/Tl1goVLI9KI/AAAAAAAAEdo/-wgWz6n2K7I/s320/07_texture.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5646775753787372706" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ajustez vos couleurs, et admirez!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-LMj-tT0dbNQ/Tl1gouARoNI/AAAAAAAAEdw/iDWQRegIbA8/s1600/08_render.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 245px;" src="http://3.bp.blogspot.com/-LMj-tT0dbNQ/Tl1gouARoNI/AAAAAAAAEdw/iDWQRegIbA8/s320/08_render.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5646775760452690130" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Maintenant, passons à la création de l'objet à exporter. D'abord, dupliquez l'astéroïde (Shift-D). Il est possible de renommer les objets en "high poly" et "low poly", par exemple, dans le menu "Object", histoire de ne pas se perdre. Enlevez le modifier de subdivisions afin de retrouver notre objet initial. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-brxNr3MODv8/Tl1gpdJv0tI/AAAAAAAAEd4/L9Pd6IlDfVw/s1600/09_low_poly.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 245px;" src="http://4.bp.blogspot.com/-brxNr3MODv8/Tl1gpdJv0tI/AAAAAAAAEd4/L9Pd6IlDfVw/s320/09_low_poly.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5646775773108884178" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ensuite, générez la texture UV (mode vertex, u, "Smart UV project"). Vous pouvez maintenant effectuer le rendu de la texture, en allant dans le tab "Render" (le petit appareil photo), et en allant tout en bas dans "Bake". Choisissez le bake mode "Normals", avec normal space "Object". Lancez le rendu avec "Bake". &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-R3qLv0JlSm4/Tl1gpvzMe9I/AAAAAAAAEeA/9GCevGxYZRw/s1600/10_bake.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 245px;" src="http://2.bp.blogspot.com/-R3qLv0JlSm4/Tl1gpvzMe9I/AAAAAAAAEeA/9GCevGxYZRw/s320/10_bake.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5646775778114567122" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Tout en haut, passez de la vue "Default" à la vue "UV editing" pour admirer votre œuvre. Sauvez l'image, puis exportez l'objet!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-0FTOnCptVmE/Tl1g9q7fiZI/AAAAAAAAEeI/dCk8U22RXFo/s1600/11_bake_results.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 245px;" src="http://1.bp.blogspot.com/-0FTOnCptVmE/Tl1g9q7fiZI/AAAAAAAAEeI/dCk8U22RXFo/s320/11_bake_results.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5646776120404576658" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Avec OSG, je transforme l'objet exporté en Wavefront (.obj) vers un .osg, puis j'édite manuellement le .osg afin de dupliquer le noeud de texture, pour ajouter une deuxième texture avec un identifiant à 1. Je change ensuite les noms pour avoir ma texture de couleurs en 0, et ma texture de normales en 1, comme l'attend mon programme.&lt;br /&gt;&lt;br /&gt;Et voilà le travail:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-PjhTJaEBMQU/Tl1tsrJwxPI/AAAAAAAAEeQ/MemY8zrmjRc/s1600/asteroid_osg.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 250px;" src="http://2.bp.blogspot.com/-PjhTJaEBMQU/Tl1tsrJwxPI/AAAAAAAAEeQ/MemY8zrmjRc/s320/asteroid_osg.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5646790122057811186" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-7056665211799492187?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/7056665211799492187/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=7056665211799492187' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7056665211799492187'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7056665211799492187'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/08/normal-maps-et-blender-25-creer-un.html' title='Normal maps et Blender 2.5 - Créer un astéroïde'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-JIyfMe4w360/Tl1gGfbpNHI/AAAAAAAAEdY/n9cKWsQdbGM/s72-c/01_initial.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-2531137911543109193</id><published>2011-08-16T23:31:00.005+02:00</published><updated>2011-08-16T23:38:08.431+02:00</updated><title type='text'>1000 cubes</title><content type='html'>Un millier de cubes orbitant tranquillement. Le système monte gentiment en charge, avec une charge CPU à 125%, c'est à dire un proc à 100% pour afficher le plus d'images possible à la seconde, et 25% en calcul d'orbites et en passage de messages.&lt;br /&gt;&lt;br /&gt;&lt;object width="320" height="266" class="BLOG_video_class" id="BLOG_video-9602249632809479" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"&gt;&lt;param name="movie" value="http://www.youtube.com/get_player"&gt;&lt;param name="bgcolor" value="#FFFFFF"&gt;&lt;param name="allowfullscreen" value="true"&gt;&lt;param name="flashvars" value="flvurl=http://v14.nonxt3.googlevideo.com/videoplayback?id%3D9602249632809479%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1330384140%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D555B1537B020932BEF9E2081CBAC303F729B1DBC.571EF7308017189D8DC49093F21DA82DF8162ADA%26key%3Dck1&amp;amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D9602249632809479%26offsetms%3D5000%26itag%3Dw160%26sigh%3DlY8JrhvwVuchrFAwpuWulH9vdvQ&amp;amp;autoplay=0&amp;amp;ps=blogger"&gt;&lt;embed src="http://www.youtube.com/get_player" type="application/x-shockwave-flash"width="320" height="266" bgcolor="#FFFFFF"flashvars="flvurl=http://v14.nonxt3.googlevideo.com/videoplayback?id%3D9602249632809479%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1330384140%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D555B1537B020932BEF9E2081CBAC303F729B1DBC.571EF7308017189D8DC49093F21DA82DF8162ADA%26key%3Dck1&amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D9602249632809479%26offsetms%3D5000%26itag%3Dw160%26sigh%3DlY8JrhvwVuchrFAwpuWulH9vdvQ&amp;autoplay=0&amp;ps=blogger"allowFullScreen="true" /&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-2531137911543109193?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/2531137911543109193/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=2531137911543109193' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2531137911543109193'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2531137911543109193'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/08/1000-cubes.html' title='1000 cubes'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-3198067498725224758</id><published>2011-08-15T23:52:00.002+02:00</published><updated>2011-08-15T23:56:36.803+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3d'/><title type='text'>Orbites</title><content type='html'>Il faut voir le cube tourner (je vais essayer de générer une vidéo), mais voilà déjà une image. Mon framework fonctionne, et devrait monter en charge facilement.&lt;br /&gt;&lt;br /&gt;Cela représente donc un cube, doué d'une vitesse initiale, orbitant autour d'une masse pour l'instant non représentée. Cela devrait prouver ou pas la possibilité de mettre à jour des centaines d'objets, et de les représenter de façon fluide en recalculant "rarement" la position et la vitesse, puis en faisant une extrapolation à chaque image.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-uiYL2Iyf6wk/TkmWAxUKToI/AAAAAAAAEcw/6sJopyfDoOg/s1600/orbit.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://1.bp.blogspot.com/-uiYL2Iyf6wk/TkmWAxUKToI/AAAAAAAAEcw/6sJopyfDoOg/s320/orbit.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5641204948240322178" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-3198067498725224758?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/3198067498725224758/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=3198067498725224758' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3198067498725224758'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3198067498725224758'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/08/orbites.html' title='Orbites'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-uiYL2Iyf6wk/TkmWAxUKToI/AAAAAAAAEcw/6sJopyfDoOg/s72-c/orbit.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-8273303268286603678</id><published>2011-08-15T00:16:00.002+02:00</published><updated>2011-08-15T00:19:22.990+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debian'/><title type='text'>Week-end de folie chez Debian</title><content type='html'>La bonne vieille Wheezy prend du poil de la bête: non seulement nous sommes passés en noyau 3.0, mais en plus Iceweasel 5 est sorti! Au menu, un très bon support de Youtube en HTML5. Peut-être vais-je enfin pouvoir me débarrasser de Flash?&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-8273303268286603678?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/8273303268286603678/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=8273303268286603678' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8273303268286603678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8273303268286603678'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/08/week-end-de-folie-chez-debian.html' title='Week-end de folie chez Debian'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4668468175948616097</id><published>2011-08-12T23:54:00.002+02:00</published><updated>2011-08-12T23:57:40.545+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Mon compilo est intelligent</title><content type='html'>Brave g++!&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;array&amp;gt;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  std::array&amp;lt;int, 5&amp;gt; a = {1, 2, 3, 4};&lt;br /&gt;  std::array&amp;lt;int, 5&amp;gt; b = {1, 2, 3, 4, 5};&lt;br /&gt;  std::array&amp;lt;int, 5&amp;gt; c = {1, 2, 3, 4, 5, 6};&lt;br /&gt;  &lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Les tableaux a et b passent comme une lettre à la poste, mais le compilo hurle fort justement sur le tableau c, avec l'on ne peut plus explicite message:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;array.cpp:9:43: error: too many initializers for ‘std::array&amp;lt;int, 5ul&amp;gt;’&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Je n'en attendais pas tant. Magnifique!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4668468175948616097?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4668468175948616097/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4668468175948616097' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4668468175948616097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4668468175948616097'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/08/mon-compilo-est-intelligent.html' title='Mon compilo est intelligent'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-6878482789048730903</id><published>2011-08-10T23:13:00.003+02:00</published><updated>2011-08-10T23:37:23.766+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Événements</title><content type='html'>Je suis en train d'essayer de construire un truc qui se tient autour de boost::asio et de la programmation orientée événements. L'idée est de construire quelques briques de plus haut niveau autour d'asio, et d'en tirer quelque chose d'utilisable. &lt;br /&gt;&lt;br /&gt;Tout tourne autour d'un boost::asio::io_service::strand, que j'ai collé dans une classe de base. J'en dérive (virtuellement!) ensuite des classes d'utilitaires tels un timer, ou un notifier / listener. Ensuite, il ne reste qu'à dériver sa classe depuis les classes d'utilitaires: l'on veut écouter tel type d'événements, recevoir un signal toutes les secondes, etc. Tout passer par le strand unique à la classe (d'où l'héritage virtuel), ce qui permet de s'affranchir complétement des locks.&lt;br /&gt;&lt;br /&gt;Cela veut également dire que l'état de l'objet ne doit être modifié que depuis le strand, ce qui n'est aucunement garanti lorsque l'on appelle une méthode de l'objet. Il faut donc réexpédier tous les appels de méthodes publiques vers une méthode privée correspondante, à travers le strand. Vu que l'on passe alors un message, il n'est plus possible d'obtenir des valeurs de retour, uniquement des callbacks ou des objets protégés.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-RMOncFXAaFg/TkL3XGu2HdI/AAAAAAAAEco/iCoV8gxK934/s1600/strand.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 209px;" src="http://3.bp.blogspot.com/-RMOncFXAaFg/TkL3XGu2HdI/AAAAAAAAEco/iCoV8gxK934/s320/strand.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5639341659737431506" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Bien évidemment, ce genre d'approche n'est utile que pour une classe limitée de problèmes. Écrire un raytracer orienté événement n'est probablement pas une bonne idée. En revanche, ces techniques pourraient bien se prêter aux jeux.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-6878482789048730903?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/6878482789048730903/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=6878482789048730903' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6878482789048730903'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6878482789048730903'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/08/evenements.html' title='Événements'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-RMOncFXAaFg/TkL3XGu2HdI/AAAAAAAAEco/iCoV8gxK934/s72-c/strand.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-5198047159663304889</id><published>2011-08-03T21:16:00.002+02:00</published><updated>2011-08-03T21:19:10.115+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debian'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Iceweasel 5 bientôt dans Squeeze!</title><content type='html'>La page d'"&lt;a href="http://qa.debian.org/excuses.php?package=iceweasel"&gt;excuses&lt;/a&gt;" de Debian: &lt;br /&gt;&lt;br /&gt;Too young, only 3 of 10 days old&lt;br /&gt;&lt;br /&gt;Il y a quelques autres points, mais j'ai bien l'impression qu'on se dirige vers un Firefox un poil moderne pour dans une semaine. Chouette!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-5198047159663304889?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/5198047159663304889/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=5198047159663304889' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5198047159663304889'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5198047159663304889'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/08/iceweasel-5-bientot-dans-squeeze.html' title='Iceweasel 5 bientôt dans Squeeze!'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-3037653366616479615</id><published>2011-08-01T22:54:00.004+02:00</published><updated>2011-08-01T23:17:58.160+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Et moi qui vous délaisse!</title><content type='html'>C'est que, entre le recrutement d'espions britanniques cherchant à se recaser (eh oui), les batailles incessantes avec un système de middleware dont le nom commence par Tib et finit par Co, et le passage une fois de plus de la souris de la main droite à la main gauche pour des raisons de santé, il faut encore que j'arrive à caser du code à moi.&lt;br /&gt;&lt;br /&gt;Le système d'update callbacks pour faire mon système de &lt;a href="http://fr.wikipedia.org/wiki/Navigation_%C3%A0_l%27estime"&gt;navigation à l'estime&lt;/a&gt; marche d'enfer: je puis passer entre mon système graphique, tournant à plusieurs centaines d'images par seconde, et le système de gamplay, tournant lui à 20 cycles, voire moins, par seconde, sans risquer ni de hacher l'un ni d'envahir l'autre. &lt;br /&gt;&lt;br /&gt;En revanche, ma nième tentative pour obtenir un bump mapping dans l'espace tangent s'est achevé par une cuisante défaite. Je n'y arrive simplement pas. Je vais donc rester aux normales dans l'espace objet, telles que je les ai gérées jusqu'à présent.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-3037653366616479615?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/3037653366616479615/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=3037653366616479615' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3037653366616479615'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3037653366616479615'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/08/et-moi-qui-vous-delaisse.html' title='Et moi qui vous délaisse!'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-1529220629768232506</id><published>2011-07-27T00:16:00.004+02:00</published><updated>2011-07-27T00:33:50.364+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Read</title><content type='html'>"Mais pourquoi", me demande mon collègue, "est-ce que mon programme fonctionne quand je le débugge, mais pas lorsque je l'exécute? On dirait qu'il attrape de mauvais paquets du réseau, et il se retrouve à lire n'importe quoi."&lt;br /&gt;&lt;br /&gt;Arf, du C#. Tentons d'y voir clair.&lt;br /&gt;&lt;br /&gt;D'habitude, j'ai absolument horreur de débugger un programme qui ne donne pas les mêmes résultats lorsqu'il tourne dans un débuggeur. Mais là, il m'a semblé que ça ne devait pas être trop difficile. Déjà, il fut facile de s'en assurer, ce n'était pas le débuggeur, mais les breakpoints. Sans breakpoints, le programme foirait, semblant effectivement lire des données pourries sur le réseau. Avec breakpoints, ça passait.&lt;br /&gt;&lt;br /&gt;Je tentais de voir quels étaient les breakpoints "magiques", en les ajoutant et les retirant suivant la rigoureuse méthode de Monte Carlo (c'est à dire au pif). Finalement, une ligne attira mon attention. Quelque chose comme:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;networkStream.Read(data, length);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Je changeais prestement la ligne pour afficher côte à côte "length" et la valeur de retour de la méthode. S'affiche:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;67889 - 1280&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Tête du collègue médusé. Eh oui. Même en C#, et comme en C, "Read" va lire et retourner ce qu'il trouve dans le tampon, et peut donc renvoyer moins que la taille demandée. Le breakpoint permettait simplement à l'ensemble du paquet d'arriver dans le tampon, et donc de faire fonctionner le programme (le contenu des données était ignoré). Mais lors d'une exécution normale, Read était appelé avant que tout le paquet ne soit arrivé. Lors de la deuxième lecture, c'était la fin du premier paquet qui passait, et qui était donc interprété en dépit du bon sens.&lt;br /&gt;&lt;br /&gt;Je dirigeais mon coreligionnaire vers une méthode à nous, répondant au doux nom de ReadExactly, et implémentée avec une belle boucle qui accumulait les Read jusqu'à la taille désirée.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-1529220629768232506?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/1529220629768232506/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=1529220629768232506' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1529220629768232506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1529220629768232506'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/07/read.html' title='Read'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-1468121112790131898</id><published>2011-07-23T00:55:00.003+02:00</published><updated>2011-07-23T01:04:46.768+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Trop de choix</title><content type='html'>&lt;pre&gt;&lt;br /&gt;void cb::EntityManager::processEvents()&lt;br /&gt;{&lt;br /&gt;  std::deque&amp;lt;std::shared_ptr&amp;lt;EntityEvent&amp;gt; &amp;gt; events;&lt;br /&gt;  m_eventQueue-&amp;gt;popAll(events);&lt;br /&gt;  &lt;font color=#ff0000&gt;// version 1&lt;br /&gt;  std::for_each(events.begin(),&lt;br /&gt;                events.end(),&lt;br /&gt;                std::bind(&amp;amp;EntityEvent::accept, std::placeholders::_1, this));&lt;/font&gt;&lt;br /&gt;  &lt;font color=#00ff00&gt;// version 2&lt;br /&gt;  for(const std::shared_ptr&amp;lt;EntityEvent&amp;gt; &amp;amp; event : events)&lt;br /&gt;  {&lt;br /&gt;    event-&amp;gt;accept(this);&lt;br /&gt;  }&lt;/font&gt;&lt;br /&gt;  &lt;font color=#0000ff&gt;// version 3&lt;br /&gt;  std::for_each(events.begin(),&lt;br /&gt;                events.end(),&lt;br /&gt;                [this](const std::shared_ptr&amp;lt;EntityEvent&amp;gt; &amp;amp; event){event-&amp;gt;accept(this);});&lt;/font&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;Et je fais comment, moi, maintenant?&lt;br /&gt;&lt;br /&gt;Autant j'adore les lambdas, autant c'est ici la solution la moins préférable: l'on a la déclaration explicite du contenu, contrairement à la solution basée sur std::bind, et l'on a l'overhead du la création de l'objet lambda, contrairement au range-based for.&lt;br /&gt;&lt;br /&gt;Au final, je crois que je la solution du range-based for me plaît plus, car elle me semble vaguement plus efficace. Il faudra que je benchmarke un peu tout ça.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-1468121112790131898?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/1468121112790131898/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=1468121112790131898' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1468121112790131898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1468121112790131898'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/07/trop-de-choix.html' title='Trop de choix'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-8344321765727033766</id><published>2011-07-20T23:19:00.004+02:00</published><updated>2011-07-20T23:36:21.101+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><category scheme='http://www.blogger.com/atom/ns#' term='emacs'/><title type='text'>Coder efficacement avec Emacs - Partie 6 - Compilation</title><content type='html'>Une de mes fonctionnalités favorites d'Emacs, c'est la console qui affiche les résultats de compilation. Il est possible de cliquer (ou d'utiliser d'absconses commandes clavier) pour aller d'erreur en erreur à travers le source. C'est quand même bien plus pratique que d'avoir la compilation dans une console à côté, et d'aller chercher le fichier et la ligne.&lt;br /&gt;&lt;br /&gt;La commande, c'est &lt;i&gt;M-x compile&lt;/i&gt;. Tout bête, mais déjà trop lorsque l'on est un serial compileur comme moi. Un petit &lt;pre&gt;(define-key global-map [f5] 'compile)&lt;/pre&gt; dans mon .emacs et voici la touche F5 affectée à la compilation. Tapons F5: la ligne de compilation par défaut apparaît. Entrée, et c'est lancé. La combinaison F5-Entrée est devenue chez moi un automatisme. L'on peut changer la ligne de compilation, qui sera maintenue tant que la session est ouverte.&lt;br /&gt;&lt;br /&gt;La commande de compilation par défaut est &lt;i&gt;make -k&lt;/i&gt;, mais il est possible de la changer pour un mode particulier. Si comme moi vous êtes un fanatique d'&lt;a href="http://omake.metaprl.org/index.html"&gt;omake&lt;/a&gt; pour compiler vos projets C ou C++:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(add-hook 'c-mode-common-hook&lt;br /&gt;  (lambda ()&lt;br /&gt;    (set (make-local-variable 'compile-command) "omake -j 4 -R")))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Et pour changer la commande par défaut hors d'un mode particulier:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;(setq compile-command "omake -j 4 -R") &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Bon codage!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-8344321765727033766?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/8344321765727033766/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=8344321765727033766' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8344321765727033766'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8344321765727033766'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/07/coder-efficacement-avec-emacs-partie-6.html' title='Coder efficacement avec Emacs - Partie 6 - Compilation'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-7923256742701526191</id><published>2011-07-17T00:02:00.003+02:00</published><updated>2011-07-17T00:29:24.879+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>C++0x - std::unique_ptr et types partiels</title><content type='html'>Prenons un exemple très simple: l'idiome "pimpl" (dont le nom m'horripile, mais bon), encore appelé "pointeur opaque". Dans le .h, on forward déclare notre type interne, que l'on définit dans le .cpp. L'idée est de cacher l'implémentation, ce qui a également l'avantage de permettre une compilation plus rapide en évitant à l'interface l'inclusion d'une myriade d'en têtes pour les types privés.&lt;br /&gt;&lt;br /&gt;Là, en bon dev C++11, l'on se dit, chic, je vais utiliser un std::unique_ptr. Voyons ce que cela donne. Ici, l'on a la classe Impl, forward déclarée, utilisée dans un std::unique_ptr, suivi d'un bout de code confirmant au compilo que l'on a bien l'intention d'instancier la classe Interface:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;memory&amp;gt;&lt;br /&gt;&lt;br /&gt;class Impl;&lt;br /&gt;&lt;br /&gt;class Interface&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  Interface();&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt;  std::unique_ptr&amp;lt;Impl&amp;gt; m_impl;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;void create()&lt;br /&gt;{&lt;br /&gt;  Interface i;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;L'on est immédiatement couvert d'injures par le compilateur:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;g++ -std=gnu++0x -c uniq.cpp&lt;br /&gt;In file included from /usr/include/c++/4.6/memory:85:0,&lt;br /&gt;                 from uniq.cpp:1:&lt;br /&gt;/usr/include/c++/4.6/bits/unique_ptr.h: In member function ‘void std::default_delete&lt;_Tp&gt;::operator()(_Tp*) const [with _Tp = Impl]’:&lt;br /&gt;/usr/include/c++/4.6/bits/unique_ptr.h:245:4:   instantiated from ‘void std::unique_ptr&lt;_Tp, _Dp&gt;::reset(std::unique_ptr&lt;_Tp, _Dp&gt;::pointer) [with _Tp = Impl, _Dp = std::default_delete&lt;Impl&gt;, std::unique_ptr&lt;_Tp, _Dp&gt;::pointer = Impl*]’&lt;br /&gt;/usr/include/c++/4.6/bits/unique_ptr.h:169:23:   instantiated from ‘std::unique_ptr&lt;_Tp, _Dp&gt;::~unique_ptr() [with _Tp = Impl, _Dp = std::default_delete&lt;Impl&gt;]’&lt;br /&gt;uniq.cpp:5:7:   instantiated from here&lt;br /&gt;/usr/include/c++/4.6/bits/unique_ptr.h:63:14: error: invalid application of ‘sizeof’ to incomplete type ‘Impl’&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Rajoutons juste un destructeur:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;memory&amp;gt;&lt;br /&gt;&lt;br /&gt;class Impl;&lt;br /&gt;&lt;br /&gt;class Interface&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  Interface();&lt;br /&gt;  ~Interface();&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt;  std::unique_ptr&amp;lt;Impl&amp;gt; m_impl;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;void create()&lt;br /&gt;{&lt;br /&gt;  Interface i;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Et g++ nous claque deux bises. &lt;br /&gt;&lt;br /&gt;En effet, et d'après &lt;a href="http://home.roadrunner.com/~hinnant/incomplete.html"&gt;ce tableau&lt;/a&gt;, contrairement à std::shared_ptr, std::unique_ptr ne peut être détruit que si son type sous-jacent est complètement défini. Dans le premier exemple, le destructeur n'est pas défini, et g++ en définit donc un par défaut, inline. Il n'a donc pas accès au type Impl, ce qui cause l'erreur. Par contre, dans le deuxième exemple, l'on a décidé de fournir un destructeur quelque part ailleurs. Le compilateur n'a donc pas besoin de générer le code pour détruire notre pointeur. Celui-ci sera généré à la définition du destructeur, probablement dans le fichier source, et donc probablement après la définition complète d'Impl.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-7923256742701526191?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/7923256742701526191/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=7923256742701526191' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7923256742701526191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7923256742701526191'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/07/c0x-stduniqueptr-et-types-partiels.html' title='C++0x - std::unique_ptr et types partiels'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4922695683774973259</id><published>2011-07-14T22:48:00.003+02:00</published><updated>2011-07-14T22:57:05.839+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='3d'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Design</title><content type='html'>Je ne suis pas convaincu par ma manière actuelle de mettre à jour mon graphe de scènes. Attendant entre chaque frame pour mettre à jour mes objets, je ne puis utiliser à fond les dernières fonctionnalités de threading d'OpenSceneGraph.&lt;br /&gt;&lt;br /&gt;J'ai donc pensé à un système de queue d'événements, qui sont lus via un callback, et mettent à jour les structures qui sont lus par les nœuds dans leurs propres callbacks de mise à jour. Ces structures seraient de la forme (timestamp, position, direction), et permettraient au nœud de mettre à jour sa position à chaque image en extrapolant.&lt;br /&gt;&lt;br /&gt;Tout est là dedans:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/--RSckjOwT18/Th9X4XprpEI/AAAAAAAAEcg/qdfN7KC-M3M/s1600/design.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 238px;" src="http://2.bp.blogspot.com/--RSckjOwT18/Th9X4XprpEI/AAAAAAAAEcg/qdfN7KC-M3M/s320/design.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5629314685169542210" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4922695683774973259?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4922695683774973259/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4922695683774973259' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4922695683774973259'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4922695683774973259'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/07/design.html' title='Design'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/--RSckjOwT18/Th9X4XprpEI/AAAAAAAAEcg/qdfN7KC-M3M/s72-c/design.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4493738872967380683</id><published>2011-07-12T00:24:00.003+02:00</published><updated>2011-07-12T00:30:26.666+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debian'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Debian downgrade</title><content type='html'>Arf, petit bug! À la suite d'un crash dans la libdbd, je ne pouvais plus démarrer le bon vieux gnucash et faire mes comptes. Downgradons donc dans la joie et la bonne humeur.&lt;br /&gt;&lt;br /&gt;Après quelques recherches, j'atterris sur la &lt;a href="http://snapshot.debian.org"&gt;page snapshot de Debian&lt;/a&gt;, dans laquelle je puis retrouver mon paquet. Je décide de passer de la 0.8.3-1+s-1 à la 0.8.2-1-4.1, et me retrouve avec un lien vers la &lt;a href="http://snapshot.debian.org/package/libdbi-drivers/0.8.2-1-4.1/#libdbd-pgsql_0.8.2-1-4.1"&gt;libdbd-pgsql 0.8.2-1-4.1&lt;/a&gt;. Un petit &lt;i&gt;dpkg -i&lt;/i&gt; plus tard, je démarre GnuCash, et miracle, j'y suis!&lt;br /&gt;&lt;br /&gt;Par contre, il va maintenant falloir faire attention à chaque fois que je mets à jour: ne pas laisser le système me remplacer ma précieuse libdbd avant que le bug soit fixé.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4493738872967380683?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4493738872967380683/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4493738872967380683' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4493738872967380683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4493738872967380683'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/07/debian-downgrade.html' title='Debian downgrade'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-3056518577542613167</id><published>2011-07-10T13:06:00.003+02:00</published><updated>2011-07-10T13:11:02.692+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debian'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>Debian, c'est comme attendre le bus...</title><content type='html'>On attend une version de gcc, et y'en a 3 qui arrivent en même temps :)&lt;br /&gt;&lt;br /&gt;Maintenant qu'avec g++4.6, on a à peu près toutes les fonctionnalités de c++0x (c++11), j'attends maintenant avec impatience la mise à jour d'Iceweasel. Les web sockets m'intriguent, et bien qu'étant un peu allergique au Javascript, j'aimerais bien expérimenter avec des applications réellement réactives.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-3056518577542613167?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/3056518577542613167/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=3056518577542613167' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3056518577542613167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3056518577542613167'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/07/debian-cest-comme-attendre-le-bus.html' title='Debian, c&apos;est comme attendre le bus...'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-5283123768689701517</id><published>2011-07-02T20:48:00.003+02:00</published><updated>2011-07-02T21:14:06.040+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>C++0x - std::set vs std::unordered_set</title><content type='html'>Il aura tout de même fallu attendre C++0x (ou devrais-je commencer à dire C++2011?) pour voir enfin apparaître les tables de hachage dans la bibliothèque standard. Diverses extensions, ansi que Boost, proposaient leurs implémentations, mais ça fait toujours plaisir de voir les choses se standardiser.&lt;br /&gt;&lt;br /&gt;Je dois cependant avouer que les tables de hachage m'ont souvent laissé un peu perplexe: leurs performances dépendent énormément du bon choix pour la fonction de hachage, ce qui rend fort difficile les prédictions. Je préfère généralement un bon arbre binaire, qui va certes nécessiter une allocation à chaque insertion et une recherche logarithmique, mais que j'ai l'impression de mieux comprendre.&lt;br /&gt;&lt;br /&gt;Voyons donc un petit benchmark afin de se faire une idée. D'un côté, le bon vieux std::set, de l'autre, le std::unordered_set. L'on insère 1000 entiers, on mesure le temps, et l'on recommence.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-liOeKqagVcs/Tg9qxfBJ1qI/AAAAAAAAEcY/-8tksJjlBDg/s1600/set_vs_hash_cumulated.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 233px;" src="http://4.bp.blogspot.com/-liOeKqagVcs/Tg9qxfBJ1qI/AAAAAAAAEcY/-8tksJjlBDg/s320/set_vs_hash_cumulated.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5624831857981511330" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-_q8-2JZL8Cs/Tg9qxe1cIpI/AAAAAAAAEcQ/lvDuLlejMFs/s1600/set_vs_hash_instant.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 232px;" src="http://3.bp.blogspot.com/-_q8-2JZL8Cs/Tg9qxe1cIpI/AAAAAAAAEcQ/lvDuLlejMFs/s320/set_vs_hash_instant.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5624831857932378770" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Comme l'on pouvait s'y attendre, l'on voit que l'insertion dans un std::set augmente de manière logarithmique. L'on voit également que l'insertion dans un std::unordered_set augmente de manière linéaire, sauf au moment des rehash: une fois que la table est trop pleine, le conteneur réalloue une nouvelle table plus grande, et y hache de nouveau chaque élément.&lt;br /&gt;&lt;br /&gt;Alors oui, le std::unordered_est est plus rapide que le std::set, sur un ensemble qui tendrait plutôt à défavoriser ce dernier: ayant utilisé des entiers consécutifs, le hachage est très efficace (c'est l'entier lui même), et il n'y a pas de collisions.&lt;br /&gt;&lt;br /&gt;Cependant, si le std::unordered_set est plus efficace sur le long terme, ses performances instantanées peuvent tout d'un coup devenir absolument horribles si l'on doit re-hacher. Un programme qui nécessite de bonnes performances à chaque insertion, et pas seulement dans l'ensemble, devra l'éviter.&lt;br /&gt;&lt;br /&gt;Une approche intéressante pour profiter des performances des tables de hachage sans payer un rehash couteux de temps en temps est d'amortir ce hachage: lorsque la table devient trop grande, l'on alloue une nouvelle table dans laquelle on met le nouvel élément. Chaque nouvelle insertion embarque avec elle quelques éléments de la vieille table, et chaque recherche vérifie les deux tables. Ainsi, au fur et à mesure, les éléments de la petite table sont déplacés dans la grande, et l'on peut se débarrasser de la petite, et recommencer le processus une fois que la grande devient à son tour trop pleine.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Voici le code du benchmark. Étrangement, la table de hachage a de meilleures performances à froid, et le std::set à chaud, ce qui est la raison pour laquelle je commence à insérer dans un set sans mesurer. Et je ne m'explique absolument pas le blip aux 3/4 de l'insertion dans le std::set, qui se reproduit à chaque exécution&lt;/i&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;chrono&amp;gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;#include &amp;lt;set&amp;gt;&lt;br /&gt;#include &amp;lt;unordered_set&amp;gt;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  int interval = 1000;&lt;br /&gt;  int points = 1000000;&lt;br /&gt;  &lt;br /&gt;  std::vector&amp;lt;std::chrono::microseconds&amp;gt; setTimes;&lt;br /&gt;  std::vector&amp;lt;std::chrono::microseconds&amp;gt; hashTimes;&lt;br /&gt;  &lt;br /&gt;  setTimes.reserve(points / interval);&lt;br /&gt;  hashTimes.reserve(points / interval);&lt;br /&gt;  &lt;br /&gt;  {&lt;br /&gt;    std::unordered_set&amp;lt;int&amp;gt; container;&lt;br /&gt;    auto base = std::chrono::system_clock::now();&lt;br /&gt;    for(int i = 0; i &amp;lt; points; ++i)&lt;br /&gt;    {&lt;br /&gt;      container.insert(i);&lt;br /&gt;      if(i % interval == 0)&lt;br /&gt;      {&lt;br /&gt;        hashTimes.push_back(std::chrono::system_clock::now() - base);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  {&lt;br /&gt;    std::set&amp;lt;int&amp;gt; container;&lt;br /&gt;    auto base = std::chrono::system_clock::now();&lt;br /&gt;    for(int i = 0; i &amp;lt; points; ++i)&lt;br /&gt;    {&lt;br /&gt;      container.insert(i);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  {&lt;br /&gt;    std::set&amp;lt;int&amp;gt; container;&lt;br /&gt;    auto base = std::chrono::system_clock::now();&lt;br /&gt;    for(int i = 0; i &amp;lt; points; ++i)&lt;br /&gt;    {&lt;br /&gt;      container.insert(i);&lt;br /&gt;      if(i % interval == 0)&lt;br /&gt;      {&lt;br /&gt;        setTimes.push_back(std::chrono::system_clock::now() - base);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  auto it = setTimes.begin();&lt;br /&gt;  auto end = setTimes.end();&lt;br /&gt;  auto it2 = hashTimes.begin();&lt;br /&gt;  for(; it != end; ++it, ++it2)&lt;br /&gt;  {&lt;br /&gt;    std::cout &amp;lt;&amp;lt; it-&amp;gt;count() &amp;lt;&amp;lt; "\t" &amp;lt;&amp;lt;  it2-&amp;gt;count() &amp;lt;&amp;lt; "\n";&lt;br /&gt;  }&lt;br /&gt;  std::cout.flush();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-5283123768689701517?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/5283123768689701517/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=5283123768689701517' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5283123768689701517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5283123768689701517'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/07/c0x-stdset-vs-stdunorderedset.html' title='C++0x - std::set vs std::unordered_set'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-liOeKqagVcs/Tg9qxfBJ1qI/AAAAAAAAEcY/-8tksJjlBDg/s72-c/set_vs_hash_cumulated.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-5392544622274932382</id><published>2011-06-23T00:01:00.002+02:00</published><updated>2011-06-23T00:03:28.183+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Commit 1024</title><content type='html'>Un beau chiffre rond pour une implémentation fonctionnelle (dans le sens paradigme, pas dans le sens qualitatif) d'une couche client serveur au dessus de boost asio.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-5392544622274932382?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/5392544622274932382/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=5392544622274932382' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5392544622274932382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5392544622274932382'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/06/commit-1024.html' title='Commit 1024'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-3304151985531897125</id><published>2011-06-18T19:17:00.002+02:00</published><updated>2011-06-18T19:32:03.961+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>g++ 4.6 et C++0x - Range based for</title><content type='html'>Petit bonus du week-end, g++4.6 débarque sur Debian Wheezy. La principale avancée concerne les "range based for", qui sonnent le glas pour la bonne vielle macro BOOST_FOREACH. &lt;br /&gt;&lt;br /&gt;Pour une macro, BOOST_FOREACH était plutôt propre et utile, mais en dehors des détails d'implémentation à s'arracher les cheveux (cherchez un peu si ça vous amuse), elle souffrait de ne pas pouvoir utiliser proprement des déclarations templates, à cause notamment des virgules. Exemple:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;boost/foreach.hpp&amp;gt;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  std::vector&amp;lt;std::pair&amp;lt;int, std::string&amp;gt; &amp;gt; v = &lt;br /&gt;    {std::make_pair(1, "a"),&lt;br /&gt;     std::make_pair(2, "b")};&lt;br /&gt;&lt;br /&gt;  BOOST_FOREACH(const std::pair&amp;lt;int, std::string&amp;gt; &amp;amp; item, v)&lt;br /&gt;  {&lt;br /&gt;    std::cout &amp;lt;&amp;lt; item.first &amp;lt;&amp;lt; " - " &amp;lt;&amp;lt; item.second &amp;lt;&amp;lt; std::endl;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Oh, la belle erreur de compile!&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;foreach.cpp:12:60: error: macro "BOOST_FOREACH" passed 3 arguments, but takes just 2&lt;br /&gt;foreach.cpp: In function ‘int main()’:&lt;br /&gt;foreach.cpp:12:3: error: ‘BOOST_FOREACH’ was not declared in this scope&lt;br /&gt;foreach.cpp:13:3: error: expected ‘;’ before ‘{’ token&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;La solution est triviale:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  typedef std::pair&amp;lt;int, std::string&amp;gt; ItemT;&lt;br /&gt;  BOOST_FOREACH(const ItemT &amp;amp; item, v)&lt;br /&gt;  {&lt;br /&gt;    std::cout &amp;lt;&amp;lt; item.first &amp;lt;&amp;lt; " - " &amp;lt;&amp;lt; item.second &amp;lt;&amp;lt; std::endl;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Triviale, mais ennuyeuse. Et non-standard. Et quand bien même utiliser des typedef pour ses types est une bonne idée, l'on on a parfois pas envie. Place donc à la solution 0x:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  std::vector&amp;lt;std::pair&amp;lt;int, std::string&amp;gt; &amp;gt; v = &lt;br /&gt;    {std::make_pair(1, "a"),&lt;br /&gt;     std::make_pair(2, "b")};&lt;br /&gt;  &lt;br /&gt;  for(const std::pair&amp;lt;int, std::string&amp;gt; &amp;amp; item : v)&lt;br /&gt;  {&lt;br /&gt;    std::cout &amp;lt;&amp;lt; item.first &amp;lt;&amp;lt; " - " &amp;lt;&amp;lt; item.second &amp;lt;&amp;lt; std::endl;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;C'est pas plus joli?&lt;br /&gt;&lt;br /&gt;Entre les range based for et les lambdas, plus aucune raison d'utiliser la macro boost, et presque plus aucune raison d'utiliser une vieille boucle for. L'est pas belle, la vie?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-3304151985531897125?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/3304151985531897125/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=3304151985531897125' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3304151985531897125'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3304151985531897125'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/06/g-46-et-c0x-range-based-for.html' title='g++ 4.6 et C++0x - Range based for'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-6474060494969526399</id><published>2011-06-12T00:17:00.002+02:00</published><updated>2011-06-12T00:33:58.573+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Asio et sockets - Un design alternatif</title><content type='html'>Jusqu'à présent, j'avais plutôt pris une route orientée objet, avec une session de base qui contient les appels socket asio dont il fallait dériver.&lt;br /&gt;&lt;br /&gt;Cependant, je suis en train de me demander si une approche purement basée sur les callbacks pourrait donner de meilleurs résultats. &lt;br /&gt;&lt;br /&gt;Je viens de commiter une classe très simple, dont on ne dérivera à priori pas, et dont voici la signature:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class SocketSession : public std::enable_shared_from_this&amp;lt;SocketSession&amp;gt;&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  SocketSession(boost::asio::io_service &amp;amp; io_service);&lt;br /&gt;  &lt;br /&gt;  void connect(const std::string &amp;amp; host,&lt;br /&gt;               int port,&lt;br /&gt;               const std::function&amp;lt;void()&amp;gt; &amp;amp; callback);&lt;br /&gt;  &lt;br /&gt;  template&amp;lt;typename BODY&amp;gt;&lt;br /&gt;  void readMessage(const std::function&amp;lt;void(const std::shared_ptr&amp;lt;Header&amp;gt; &amp;amp;, &lt;br /&gt;                                            const std::shared_ptr&amp;lt;BODY&amp;gt; &amp;amp;)&amp;gt;&lt;br /&gt;                                            &amp;amp; callback);&lt;br /&gt;&lt;br /&gt;  template&amp;lt;typename BODY&amp;gt;&lt;br /&gt;  void sendMessage(const BODY &amp;amp; body);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Toutes les méthodes publiques sont thread safe, car appelant en interne les méthodes correspondantes à travers un strand. L'appelant, lui, se contente de passer les callbacks, lequels peuvent être également protégés par leur propre strand.&lt;br /&gt;&lt;br /&gt;Avantages:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Le système est complètement thread safe&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Pas besoin de locks, les appels sont tous protégés par le strand. C'est particulièrement utile pour l'envoi de messages, puisqu'il faut pousser les messages dans une queue afin de n'avoir qu'un seul appel à async_write&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Contrairement à mon implémentation "dérivante", la partie socket pourra tourner de manière concurrente avec l'appelant, ce qui pourrait permettre une meilleure montée en charge (à vérifier, cependant). Tout du moins, en laissant à l'utilisateur de la classe le choix de protéger ses callbacks à travers un strand, on peut permettre une meilleure parallélisation lorsque c'est possible&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;L'inconvénient majeur est la multiplication des callbacks, et donc de copies et d'allocations.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-6474060494969526399?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/6474060494969526399/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=6474060494969526399' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6474060494969526399'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6474060494969526399'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/06/asio-et-sockets-un-design-alternatif.html' title='Asio et sockets - Un design alternatif'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-2455821019989709208</id><published>2011-06-08T22:18:00.004+02:00</published><updated>2011-06-08T22:43:12.990+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='postgres'/><title type='text'>Postgresql et encore plus de requêtes récursives</title><content type='html'>L'on m'a posé récemment un intéressant problème de base de données qui pourrait se traduire ainsi: étant donné la liste d'employés suivante, déterminer le premier directeur auquel se rattache chaque employé:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;create table employees(&lt;br /&gt; id integer not null,&lt;br /&gt; name text not null,&lt;br /&gt; level text not null,&lt;br /&gt; manager_id integer null);&lt;br /&gt;&lt;br /&gt;insert into employees values&lt;br /&gt;(1, 'Anne', 'CEO', null),&lt;br /&gt;(2, 'Barbara', 'Director', 1),&lt;br /&gt;(3, 'Carole', 'Director', 2),&lt;br /&gt;(4, 'Delphine', 'Director', 2),&lt;br /&gt;(5, 'Eleonore', 'Supervisor', 2),&lt;br /&gt;(6, 'Fanny', 'Supervisor', 3),&lt;br /&gt;(7, 'Gwen', 'Supervisor', 5),&lt;br /&gt;(8, 'Henriette', 'Supervisor', 7),&lt;br /&gt;(9, 'Isabelle', 'Employee', 5),&lt;br /&gt;(10, 'Juliette', 'Employee', 6),&lt;br /&gt;(11, 'Kariane', 'Employee', 5),&lt;br /&gt;(12, 'Lucie', 'Employee', 4);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;La première étape est de pondre une requête récursive, nous donnant pour chaque employé la liste de ses chefs. L'on tiendra à jour également la distance hiérarchique:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;with recursive managers(employee_id, manager_id, depth) as(&lt;br /&gt;select id, manager_id, 1 from employees&lt;br /&gt; union&lt;br /&gt;select m.employee_id, e.manager_id, m.depth + 1&lt;br /&gt;from managers m&lt;br /&gt;join employees e on m.manager_id = e.id)&lt;br /&gt;select &lt;br /&gt; e1.id, &lt;br /&gt; e1.name, &lt;br /&gt; m.depth, &lt;br /&gt; e2.id, &lt;br /&gt; e2.name, &lt;br /&gt; e2.level&lt;br /&gt;from managers m&lt;br /&gt;join employees e1 on m.employee_id = e1.id&lt;br /&gt;join employees e2 on m.manager_id = e2.id&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Cette requête retourne les résultats suivants:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;2,Barbara,1,1,Anne,CEO&lt;br /&gt;3,Carole,1,2,Barbara,Director&lt;br /&gt;4,Delphine,1,2,Barbara,Director&lt;br /&gt;5,Eleonore,1,2,Barbara,Director&lt;br /&gt;6,Fanny,1,3,Carole,Director&lt;br /&gt;7,Gwen,1,5,Eleonore,Supervisor&lt;br /&gt;8,Henriette,1,7,Gwen,Supervisor&lt;br /&gt;9,Isabelle,1,5,Eleonore,Supervisor&lt;br /&gt;10,Juliette,1,6,Fanny,Supervisor&lt;br /&gt;11,Kariane,1,5,Eleonore,Supervisor&lt;br /&gt;12,Lucie,1,4,Delphine,Director&lt;br /&gt;3,Carole,2,1,Anne,CEO&lt;br /&gt;4,Delphine,2,1,Anne,CEO&lt;br /&gt;5,Eleonore,2,1,Anne,CEO&lt;br /&gt;6,Fanny,2,2,Barbara,Director&lt;br /&gt;7,Gwen,2,2,Barbara,Director&lt;br /&gt;8,Henriette,2,5,Eleonore,Supervisor&lt;br /&gt;9,Isabelle,2,2,Barbara,Director&lt;br /&gt;10,Juliette,2,3,Carole,Director&lt;br /&gt;11,Kariane,2,2,Barbara,Director&lt;br /&gt;12,Lucie,2,2,Barbara,Director&lt;br /&gt;6,Fanny,3,1,Anne,CEO&lt;br /&gt;7,Gwen,3,1,Anne,CEO&lt;br /&gt;8,Henriette,3,2,Barbara,Director&lt;br /&gt;9,Isabelle,3,1,Anne,CEO&lt;br /&gt;10,Juliette,3,2,Barbara,Director&lt;br /&gt;11,Kariane,3,1,Anne,CEO&lt;br /&gt;12,Lucie,3,1,Anne,CEO&lt;br /&gt;8,Henriette,4,1,Anne,CEO&lt;br /&gt;10,Juliette,4,1,Anne,CEO&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;On approche. Prenons donc seulement le cas où un chef est un directeur, et voyons ce que cela donne:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;with recursive managers(employee_id, manager_id, depth) as(&lt;br /&gt;select id, manager_id, 1 from employees&lt;br /&gt; union&lt;br /&gt;select m.employee_id, e.manager_id, m.depth + 1&lt;br /&gt;from managers m&lt;br /&gt;join employees e on m.manager_id = e.id)&lt;br /&gt;select &lt;br /&gt; e1.id, &lt;br /&gt; e1.name, &lt;br /&gt; m.depth, &lt;br /&gt; e2.id, &lt;br /&gt; e2.name, &lt;br /&gt; e2.level&lt;br /&gt;from managers m&lt;br /&gt;join employees e1 on m.employee_id = e1.id&lt;br /&gt;join employees e2 on m.manager_id = e2.id&lt;br /&gt;where e2.level = 'Director'&lt;br /&gt;&lt;br /&gt;3,Carole,1,2,Barbara,Director&lt;br /&gt;4,Delphine,1,2,Barbara,Director&lt;br /&gt;5,Eleonore,1,2,Barbara,Director&lt;br /&gt;6,Fanny,2,2,Barbara,Director&lt;br /&gt;6,Fanny,1,3,Carole,Director&lt;br /&gt;7,Gwen,2,2,Barbara,Director&lt;br /&gt;8,Henriette,3,2,Barbara,Director&lt;br /&gt;9,Isabelle,2,2,Barbara,Director&lt;br /&gt;10,Juliette,3,2,Barbara,Director&lt;br /&gt;10,Juliette,2,3,Carole,Director&lt;br /&gt;11,Kariane,2,2,Barbara,Director&lt;br /&gt;12,Lucie,2,2,Barbara,Director&lt;br /&gt;12,Lucie,1,4,Delphine,Director&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Mieux! Mais comme parfois un directeur dépend d'un autre directeur, les pauvres Fanny, Juliette et Lucie sont en double. Il faut donc ne récupérer pour un employé que le cas où la profondeur est la plus basse. Cela donne des requêtes plutôt ésotériques en vieux SQL. Mais une fois de plus, la modernité nous tend les bras, et les window function permettent de résoudre le problème (presque) immédiatement. Prenons donc la fonction &lt;i&gt;rank()&lt;/i&gt;, qui retourne le rang d'une ligne sur une certaine partition. Nous cherchons donc le rang d'une ligne d'employé, partitionné sur cet employé, et ordonné par la profondeur:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;with recursive managers(employee_id, manager_id, depth) as(&lt;br /&gt;select id, manager_id, 1 from employees&lt;br /&gt; union&lt;br /&gt;select m.employee_id, e.manager_id, m.depth + 1&lt;br /&gt;from managers m&lt;br /&gt;join employees e on m.manager_id = e.id)&lt;br /&gt;select &lt;br /&gt; e1.name as employee_name, &lt;br /&gt; e2.name as director_name, &lt;br /&gt; rank() over (partition by e1.name order by depth)&lt;br /&gt;from managers m&lt;br /&gt;join employees e1 on m.employee_id = e1.id&lt;br /&gt;join employees e2 on m.manager_id = e2.id&lt;br /&gt;where e2.level = 'Director'&lt;br /&gt;&lt;br /&gt;Carole,Barbara,1&lt;br /&gt;Delphine,Barbara,1&lt;br /&gt;Eleonore,Barbara,1&lt;br /&gt;Fanny,Carole,1&lt;br /&gt;Fanny,Barbara,2&lt;br /&gt;Gwen,Barbara,1&lt;br /&gt;Henriette,Barbara,1&lt;br /&gt;Isabelle,Barbara,1&lt;br /&gt;Juliette,Carole,1&lt;br /&gt;Juliette,Barbara,2&lt;br /&gt;Kariane,Barbara,1&lt;br /&gt;Lucie,Delphine,1&lt;br /&gt;Lucie,Barbara,2&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;On y est presque. Nous voilà donc avec le rang basé sur la profondeur, par nom. Lucie dépend donc d'abord de Delphine, et ensuite de Barbara. Maintenant, obtenir le résultat final est trivial:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;select employee_name, director_name &lt;br /&gt;from&lt;br /&gt;(&lt;br /&gt; with recursive managers(employee_id, manager_id, depth) as(&lt;br /&gt; select id, manager_id, 1 from employees&lt;br /&gt;  union&lt;br /&gt; select m.employee_id, e.manager_id, m.depth + 1&lt;br /&gt; from managers m&lt;br /&gt; join employees e on m.manager_id = e.id)&lt;br /&gt; select &lt;br /&gt;  e1.name as employee_name, &lt;br /&gt;  e2.name as director_name, &lt;br /&gt;  rank() over (partition by e1.name order by depth)&lt;br /&gt; from managers m&lt;br /&gt; join employees e1 on m.employee_id = e1.id&lt;br /&gt; join employees e2 on m.manager_id = e2.id&lt;br /&gt; where e2.level = 'Director'&lt;br /&gt;) t&lt;br /&gt;where rank = 1&lt;br /&gt;&lt;br /&gt;Carole,Barbara&lt;br /&gt;Delphine,Barbara&lt;br /&gt;Eleonore,Barbara&lt;br /&gt;Fanny,Carole&lt;br /&gt;Gwen,Barbara&lt;br /&gt;Henriette,Barbara&lt;br /&gt;Isabelle,Barbara&lt;br /&gt;Juliette,Carole&lt;br /&gt;Kariane,Barbara&lt;br /&gt;Lucie,Delphine&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;La requête n'est certes pas tout à fait basique, mais elle est relativement claire grâce à la séparation entre la partie récursive d'abord, la window fonction ensuite, et enfin la sur-requête finale pour présenter les résultats. Sans ces outils, l'on aurait eu une panoplie de sous-requêtes se joignant elles-mêmes, pour un résultat bien moins propre, et bien moins efficace.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-2455821019989709208?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/2455821019989709208/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=2455821019989709208' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2455821019989709208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2455821019989709208'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/06/postgresql-et-encore-plus-de-requetes.html' title='Postgresql et encore plus de requêtes récursives'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-6163119040796025216</id><published>2011-06-05T00:19:00.002+02:00</published><updated>2011-06-05T00:32:54.474+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Plus d'asio, et copy_if</title><content type='html'>Je me remets à Asio, et j'essaie notamment de ré-implémenter un handler potable pour mes connections socket en multithreadé. L'idée est également d'abstraire un peu toute la cochonnerie derrière, afin de pouvoir implémenter très proprement son protocole à l'aide de callbacks. J'espère obtenir quelque chose de suffisamment puissant et réactif avec une intégration asynchrone avec un pool de connections vers la base. &lt;br /&gt;&lt;br /&gt;Dans un tout autre registre, je me suis battu récemment avec la STL, et notamment avec l'absence de copy_if. Ce que je voulais vraiment:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;std::copy_if(input.begin(),&lt;br /&gt;             input.end(),&lt;br /&gt;             std::back_inserter(output),&lt;br /&gt;             boost::bind(&amp;Class::predicate, this, _1));&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Mais, copy_if ayant (selon Stroustrup) été oublié, il faut faire avec et utiliser remove_copy_if, qui fait exactement l'inverse. Je me suis battu avec des std::not1 et des bind dans tous les sens, sans arriver à faire compiler la chose. En fait, c'était tout bête.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;std::remove_copy_if(input.begin(),&lt;br /&gt;                    input.end(),&lt;br /&gt;                    std::back_inserter(output),&lt;br /&gt;                    !boost::bind(&amp;Class::predicate, this, _1));&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Pourquoi ça marche? J'avoue que je ne comprends pas vraiment le fonctionnement interne de bind, et que je le vois plus comme un pointeur sur fonction, avec lequel un ! ne fonctionnerait pas. C'est donc assez magique.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-6163119040796025216?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/6163119040796025216/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=6163119040796025216' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6163119040796025216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6163119040796025216'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/06/plus-dasio-et-copyif.html' title='Plus d&apos;asio, et copy_if'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-6682051458436206137</id><published>2011-06-03T22:38:00.004+02:00</published><updated>2011-06-03T22:55:01.755+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Valgrind massif - Mémoire un peu trop vive</title><content type='html'>Je me suis mis à utiliser &lt;a href="http://valgrind.org/docs/manual/ms-manual.html"&gt;massif&lt;/a&gt; de la suite Valgrind, destiné à mesurer l'utilisation mémoire d'un programme au cours du temps, plus spécifiquement du tas (c'est à dire de la mémoire allouée via malloc/new).&lt;br /&gt;&lt;br /&gt;L'outil est très bien tourné: il suffit de compiler son programme avec -g, et de le faire tourner sous massif. Un petit rapport est généré, contenant un certain nombre de snapshots avec le détail de l'utilisation mémoire, et la liste des appels l'ayant générée. &lt;br /&gt;&lt;br /&gt;C'est là que l'on retrouve nos bonnes vieilles structures de données: les std::set et les std::map sont des structures tout à fait épatantes, mais l'overhead est significatif. L'on retrouvera ainsi quelles structures bénéficieraient d'une transformation vers un std::deque trié, par exemple. &lt;br /&gt;&lt;br /&gt;C'est également une bonne manière de trouver les buffers qui grandissent perpétuellement. Un bout de code qui lirait les paquets venus du réseau pourrait par exemple être implémenté avec un vecteur effectuant des resize() pour redimensionner à la taille du paquet. Mais si resize() peut augmenter la capacité si besoin, il ne la réduit jamais! La seule manière de réduire proprement un vecteur, c'est de l'échanger avec un vecteur tout neuf. Démonstration:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  std::vector&amp;lt;int&amp;gt; a;&lt;br /&gt;  &lt;br /&gt;  std::cout &amp;lt;&amp;lt; "size\tcapacity\n";&lt;br /&gt;  std::cout &amp;lt;&amp;lt; a.size() &amp;lt;&amp;lt; "\t" &amp;lt;&amp;lt; a.capacity() &amp;lt;&amp;lt; "\n";&lt;br /&gt;  &lt;br /&gt;  a.resize(10000);&lt;br /&gt;&lt;br /&gt;  std::cout &amp;lt;&amp;lt; a.size() &amp;lt;&amp;lt; "\t" &amp;lt;&amp;lt; a.capacity() &amp;lt;&amp;lt; "\n";&lt;br /&gt;&lt;br /&gt;  a.resize(1);&lt;br /&gt;&lt;br /&gt;  std::cout &amp;lt;&amp;lt; a.size() &amp;lt;&amp;lt; "\t" &amp;lt;&amp;lt; a.capacity() &amp;lt;&amp;lt; "\n";&lt;br /&gt;  &lt;br /&gt;  std::vector&amp;lt;int&amp;gt; b(a.begin(), a.end());&lt;br /&gt;  std::swap(b, a);&lt;br /&gt;&lt;br /&gt;  std::cout &amp;lt;&amp;lt; a.size() &amp;lt;&amp;lt; "\t" &amp;lt;&amp;lt; a.capacity() &amp;lt;&amp;lt; "\n";&lt;br /&gt;&lt;br /&gt;  std::cout.flush();&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;À l'exécution:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;size    capacity&lt;br /&gt;0       0&lt;br /&gt;10000   10000&lt;br /&gt;1       10000&lt;br /&gt;1       1&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-6682051458436206137?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/6682051458436206137/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=6682051458436206137' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6682051458436206137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6682051458436206137'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/06/valgrind-massif-memoire-un-peu-trop.html' title='Valgrind massif - Mémoire un peu trop vive'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-7271637039367221009</id><published>2011-06-03T00:28:00.003+02:00</published><updated>2011-06-03T00:40:28.734+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='monde'/><category scheme='http://www.blogger.com/atom/ns#' term='postgres'/><title type='text'>La lib geos</title><content type='html'>La bibliothèque &lt;a href="http://trac.osgeo.org/geos/"&gt;geos&lt;/a&gt; permet de gérer des objets géométriques en vue d'une intégration avec divers logiciels de gestion de données géographiques. L'on remarquera en particulier le support du format WKB (pour Well Known Binary) qui le rend donc compatible (efficacement!) avec Postgresql/Postgis. &lt;br /&gt;&lt;br /&gt;J'étudie actuellement la possibilité d'utiliser ces outils pour gérer mes mondes OpenRailz. Le gros intérêt est d'avoir déjà tout un tas d'opérations sur les géométries. Les défauts sont tout une plus grande difficulté d'intégration (pas de visiteurs, donc probablement besoin de faire de moches dynamic_cast pour afficher la géométrie, par exemple), des std::auto_ptr un peu partout qui vont faire hurler mon compilo C++0x, et enfin probablement des soucis pour gérer les objets 3D correctement.&lt;br /&gt;&lt;br /&gt;J'imagine qu'en considérant un certain nombre de couches horizontales dans le monde, l'on peut se ramener à des problèmes en 2D dans chaque couche.&lt;br /&gt;&lt;br /&gt;Première étape, pondre un schéma de BDD qui tienne la route.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-7271637039367221009?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/7271637039367221009/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=7271637039367221009' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7271637039367221009'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7271637039367221009'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/06/la-lib-geos.html' title='La lib geos'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-5495081697192014031</id><published>2011-05-26T00:16:00.002+02:00</published><updated>2011-05-26T00:20:21.876+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='postgres'/><title type='text'>Postgresql et Postgis pour l'aviation</title><content type='html'>Découvert via le &lt;a href=""&gt;planet&lt;/a&gt; de Postgresql, une &lt;a href="http://www.pgcon.org/2011/schedule/attachments/195_Using%20PostgreSQL%20for%20Flight%20Planning.pdf"&gt;excellente présentation&lt;/a&gt; d'une utilisation de Postgis, le module Postgresql de gestion des données géographiques, dans le domaine de l'aviation, et plus particulièrement de la gestion des plans de vols.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-5495081697192014031?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/5495081697192014031/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=5495081697192014031' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5495081697192014031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5495081697192014031'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/05/postgresql-et-postgis-pour-laviation.html' title='Postgresql et Postgis pour l&apos;aviation'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-5011971666736838965</id><published>2011-05-16T23:34:00.002+02:00</published><updated>2011-05-16T23:38:46.011+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><title type='text'>XSD - Pas évident</title><content type='html'>Assez moches, finalement, les schémas XSD. Documentation absconse, grammaire peu claire, et bien trop de façons de générer la même chose.&lt;br /&gt;&lt;br /&gt;C'est que j'essaie de reprendre le bon vieux &lt;a href="http://aubedesheros.blogspot.com/2007/11/mlxsd-comme-sur-des-roulettes.html"&gt;mlxsd&lt;/a&gt; et de le rendre un peu plus respectueux des standards. Et c'est pas de la tarte.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-5011971666736838965?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/5011971666736838965/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=5011971666736838965' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5011971666736838965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5011971666736838965'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/05/xsd-pas-evident.html' title='XSD - Pas évident'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-3414294984490768613</id><published>2011-05-02T18:00:00.004+02:00</published><updated>2011-05-02T23:50:52.258+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Ocaml Lwt - Mini tutorial</title><content type='html'>Connaissez-vous &lt;a href="http://ocsigen.org/lwt/manual/"&gt;Lwt&lt;/a&gt;? C'est une bibliothèque proposant un modèle asynchrone autour des &lt;a href="http://fr.wikipedia.org/wiki/Fibre_%28informatique%29"&gt;fibres&lt;/a&gt;, ou threads légers (déjà qu'un thread était un processus léger, est-ce qu'une fibre est un processus vachement léger?) coopératifs, c'est à dire que la fibre va s'exécuter jusqu'à ce qu'elle laisse le champ libre à une autre fibre, via des appels spéciaux, par exemple pour effectuer des opérations d'entrée sortie, ou attendre un résultat fourni par une autre fibre.&lt;br /&gt;&lt;br /&gt;Je trouve le manuel un poil léger, donc voici une série d'exemples très simples pour se faire une idée de l'utilisation du bazar. L'idée est généralement de créer un thread lwt, puis de le faire tourner via un appel à Lwt_main.run jusqu'à ce que l'exécution du thread soit complétée, et d'en récupérer une valeur de retour.&lt;br /&gt;&lt;br /&gt;Dans un terminal ocaml, ces commandes permettent de charger les bibliothèques lwt:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#use "topfind";;&lt;br /&gt;#require "lwt";;&lt;br /&gt;#require "lwt.extra";;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;C'est parti. L'exemple le plus simple: ce bout de code créé un bête thread lwt déjà terminé, contenant la valeur 3. Le &lt;i&gt;Lwt_main.run&lt;/i&gt; attend que le thread soit complété et en retourne la valeur. Dans ce cas, il n'a rien à faire que de simplement retourner 3.&lt;br /&gt;&lt;pre&gt;let t = Lwt.return 3 in&lt;br /&gt;Lwt_main.run t&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Un premier exemple faisant enfin quelque chose: l'on utilise la fonction &lt;i&gt;Lwt_unix.sleep&lt;/i&gt;, lequel retourne un thread qui se termine au bout d'un certain temps. Cette fonction va donc dormir pendant 2 secondes avant de retourner &lt;i&gt;unit&lt;/i&gt;.&lt;br /&gt;&lt;pre&gt;let t = Lwt_unix.sleep 2. in&lt;br /&gt;Lwt_main.run t&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Voici l'utilisation d'une routine d'entrée sortie. Parce que les threads sont coopératifs, il est nécessaire de ne jamais bloquer ou utiliser des fonctions d'entrée / sortie non bénies par lwt. L'on utilisera donc &lt;i&gt;Lwt_io&lt;/i&gt; pour lire et écrire des fichiers ou les entrées sorties standard. Le modèle est le même: notre thread écrit "Miaou" sur la sortie standard, et le thread est complété.&lt;br /&gt;&lt;pre&gt;let t = Lwt_io.write_line &lt;br /&gt;  Lwt_io.stdout&lt;br /&gt;  "Miaou"&lt;br /&gt;in&lt;br /&gt;Lwt_main.run t&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ah, la fonction &lt;i&gt;Lwt.bind&lt;/i&gt;! Elle permet de chaîner les threads: quand un thread est complété, il passe son résultat au suivant, qui s'exécute à son tour. Dans notre cas, le plus simple, nous passons &lt;i&gt;unit&lt;/i&gt; à la fonction qui écrit. Vous l'aurez deviné, ce bout de code attend 2 secondes, puis affiche "Miaou" à l'écran.&lt;br /&gt;&lt;pre&gt;let t = &lt;br /&gt;  Lwt.bind&lt;br /&gt;    (Lwt_unix.sleep 2.)&lt;br /&gt;    (fun () -&gt; Lwt_io.write_line Lwt_io.stdout "Miaou")&lt;br /&gt;in&lt;br /&gt;Lwt_main.run t&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Enfin, un exemple démontrant les capacités asynchrones de Lwt. Dans cet exemple, l'on créé 3 threads qui chacun attendent un certain temps avant d'afficher un message. La fonction &lt;i&gt;Lwt.join&lt;/i&gt; retourne une fois que les 3 threads sont complétés. Quelque soit l'ordre dans lequel les threads ont été passés à la fonction, ils s'afficheront bien en temps voulu.&lt;br /&gt;&lt;pre&gt;let sleep_and_print duration message = &lt;br /&gt;  Lwt.bind&lt;br /&gt;    (Lwt_unix.sleep duration)&lt;br /&gt;    (fun () -&gt; Lwt_io.write_line Lwt_io.stdout message)&lt;br /&gt;in&lt;br /&gt;let t = Lwt.join&lt;br /&gt;  [sleep_and_print 3. "3 secondes";&lt;br /&gt;   sleep_and_print 4. "4 secondes";&lt;br /&gt;   sleep_and_print 2. "2 secondes"]&lt;br /&gt;in&lt;br /&gt;Lwt_main.run t&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Voilà les bases, à partir de là il ne s'agit plus que de chaîner les fonctions d'entrées sorties Lwt décrites dans le manuel. &lt;br /&gt;&lt;br /&gt;J'ai l'intention d'essayer d'écrire un petit moteur asynchrone orienté événements, permettant à l'utilisateur de souscrire dynamiquement à un certain nombre d'entrées, comme par exemple une horloge, des entrées réseau, ou des passages de messages (probablement pas pour OpenRailz, mais on ne sait jamais...).&lt;br /&gt;&lt;br /&gt;Le mot de la fin: OCaml ne permet pas l'exécution concurrente de code car il possède, tout comme Python d'ailleurs, un verrou global. Lwt ne change pas cette règle, et n'est donc pas orienté vers du "number crunching", par exemple, mais permet en revanche de designer de manière très élégante des applications réactives devant gérer des événements complexes. Les appels coopératifs s'assurent que l'application n'est jamais en train d'attendre alors qu'un autre bout de code pourrait être exécuté, ce qui permet d'aller taper dans la base de données, écouter des messages réseau, lire des fichiers, et logger dans d'autres d'une manière transparente et claire. Cool non?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-3414294984490768613?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/3414294984490768613/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=3414294984490768613' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3414294984490768613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3414294984490768613'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/05/ocaml-lwt-mini-tutorial.html' title='Ocaml Lwt - Mini tutorial'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-1149065920054079340</id><published>2011-04-24T12:02:00.004+02:00</published><updated>2011-04-24T12:18:41.702+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Performances: Asio custom alloc</title><content type='html'>Reprenant le post précédent, je me suis demandé quel était l'effet des allocations sur les performances. Puisqu'Asio permet de customiser ses allocateurs, j'ai adapté l'exemple &lt;a href="http://www.boost.org/doc/libs/1_42_0/doc/html/boost_asio/example/allocation/server.cpp"&gt;fourni par Asio&lt;/a&gt; à ma comparaison boost::bind contre lambda.&lt;br /&gt;&lt;br /&gt;Tout d'abord, Valgrind confirme effectivement que les allocations sont parties (test réduit à 2000 tâches, sinon ça prenait la nuit):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;==3194== Memcheck, a memory error detector&lt;br /&gt;==3194== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.&lt;br /&gt;==3194== HEAP SUMMARY:&lt;br /&gt;==3194==     in use at exit: 0 bytes in 0 blocks&lt;br /&gt;==3194==   total heap usage: 2,006 allocs, 2,006 frees, 96,496 bytes allocated&lt;br /&gt;&lt;br /&gt;==3205== Memcheck, a memory error detector&lt;br /&gt;==3205== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.&lt;br /&gt;==3205== HEAP SUMMARY:&lt;br /&gt;==3205==     in use at exit: 0 bytes in 0 blocks&lt;br /&gt;==3205==   total heap usage: 6 allocs, 6 frees, 496 bytes allocated&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ensuite, étonnamment, les performances ne sont pas si différentes:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-yAGni45K_Yw/TbP2a9ssMRI/AAAAAAAAEbc/ExhdNBtjRh0/s1600/asio_alloc.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 302px; height: 320px;" src="http://1.bp.blogspot.com/-yAGni45K_Yw/TbP2a9ssMRI/AAAAAAAAEbc/ExhdNBtjRh0/s320/asio_alloc.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5599089704850698514" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;J'avais imaginé que le million d'allocations prendrait la part du lion dans l'exécution du programme, mais de fait l'on ne parle que d'une différence de 10%. C'est toujours bon à prendre, mais loin d'être un miracle. &lt;br /&gt;&lt;br /&gt;Pour un gain de 0.15μs par allocation, il me semble inutile de se fatiguer à passer par un allocateur fait à la mimine, à part peut-être dans les cas extrêmes où l'on cherche à réduire la latence par tous les moyens.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-1149065920054079340?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/1149065920054079340/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=1149065920054079340' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1149065920054079340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1149065920054079340'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/04/performances-asio-custom-alloc.html' title='Performances: Asio custom alloc'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-yAGni45K_Yw/TbP2a9ssMRI/AAAAAAAAEbc/ExhdNBtjRh0/s72-c/asio_alloc.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-5632459925730501653</id><published>2011-04-20T22:48:00.002+02:00</published><updated>2011-04-20T22:59:05.699+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Performances: lambda vs boost::bind</title><content type='html'>Maintenant que l'on a les lambdas, peut-on se passer de boost::bind? Et qui est le plus rapide?&lt;br /&gt;&lt;br /&gt;Voici un petit programme qui fait tourner un certain nombre de "tâches" de manière asynchrone à travers le framework asio, en passant un handler soit via un (une?) lambda, soit un boost::bind.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;chrono&amp;gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;boost/asio.hpp&amp;gt;&lt;br /&gt;#include &amp;lt;boost/bind.hpp&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;class Recursive&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  Recursive(boost::asio::io_service &amp;amp; io_service,&lt;br /&gt;            bool lambda,&lt;br /&gt;            int max):&lt;br /&gt;    m_io_service(io_service),&lt;br /&gt;    m_lambda(lambda),&lt;br /&gt;    m_max(max)&lt;br /&gt;  {&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  void run(int i)&lt;br /&gt;  {&lt;br /&gt;    if(i &amp;lt; m_max)&lt;br /&gt;    {&lt;br /&gt;      if(m_lambda)&lt;br /&gt;      {&lt;br /&gt;        m_io_service.post([this, i](){run(i + 1);});&lt;br /&gt;      }&lt;br /&gt;      else&lt;br /&gt;      {&lt;br /&gt;        m_io_service.post(boost::bind(&amp;amp;Recursive::run,&lt;br /&gt;                                      this,&lt;br /&gt;                                      i + 1));&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;private:&lt;br /&gt;  boost::asio::io_service &amp;amp; m_io_service;&lt;br /&gt;  bool m_lambda;&lt;br /&gt;  int m_max;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  {&lt;br /&gt;    boost::asio::io_service io_service;&lt;br /&gt;    Recursive rec(io_service, true, 10000000);&lt;br /&gt;    io_service.post([&amp;amp;rec](){rec.run(0);});&lt;br /&gt;    &lt;br /&gt;    auto t1 = std::chrono::system_clock::now();&lt;br /&gt;    &lt;br /&gt;    io_service.run();&lt;br /&gt;    &lt;br /&gt;    auto t2 = std::chrono::system_clock::now();&lt;br /&gt;    std::cout &amp;lt;&amp;lt; "lambda: " &amp;lt;&amp;lt; (t2 - t1).count() &amp;lt;&amp;lt; std::endl;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  {&lt;br /&gt;    boost::asio::io_service io_service;&lt;br /&gt;    Recursive rec(io_service, false, 10000000);&lt;br /&gt;    io_service.post([&amp;amp;rec](){rec.run(0);});&lt;br /&gt;    &lt;br /&gt;    auto t1 = std::chrono::system_clock::now();&lt;br /&gt;    &lt;br /&gt;    io_service.run();&lt;br /&gt;    &lt;br /&gt;    auto t2 = std::chrono::system_clock::now();&lt;br /&gt;    std::cout &amp;lt;&amp;lt; "bind: " &amp;lt;&amp;lt; (t2 - t1).count() &amp;lt;&amp;lt; std::endl;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Eh bien, les braves petites lambdas sont significativement plus rapides que boost::bind, d'environ 5 à 6 %. Il ne s'agit pas d'allocations, valgrind confirmant que les allocations mémoire restent les mêmes. Peut-être le foncteur correspondant à un boost::bind est-il plus compliqué à construire.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-5632459925730501653?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/5632459925730501653/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=5632459925730501653' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5632459925730501653'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5632459925730501653'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/04/performances-lambda-vs-boostbind.html' title='Performances: lambda vs boost::bind'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-8586544502852625619</id><published>2011-04-13T01:44:00.002+02:00</published><updated>2011-04-13T01:52:51.084+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debian'/><category scheme='http://www.blogger.com/atom/ns#' term='3d'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Fglrx sur Debian - Encore des histoires</title><content type='html'>Ça faisait longtemps que ça n'avait pas foiré, j'avais donc perdu l'habitude. Le retour de manivelle fut rude: avec l'arrivée du noyau 2.6.38, le serveur X m'a sauté à la figure avec ses habituels "fglrx(0): ACPI: DRM connection failed", "atiddxDriScreenInit failed", pour finir par segfaulter lamentablement. &lt;br /&gt;&lt;br /&gt;Une petite recherche finit par me convaincre que le module noyau n'était tout simplement pas présent. À l'installation et à la désinstallation du module fglrx-modules-dkms, je voyais bien la compile pour les noyaux 2.6.30 et 2.6.32, mais pas pour le nouveau menu.&lt;br /&gt;&lt;br /&gt;Finalement, c'était tout bête. Il me fallait simplement les kernel headers 2.6.38. Un petit "aptitude install linux-headers-2.6.38-2-amd64", lequel automatiquement construit tous les modules nécessaires, et je suis de retour avec l'accélération matérielle.&lt;br /&gt;&lt;br /&gt;Ouf.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-8586544502852625619?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/8586544502852625619/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=8586544502852625619' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8586544502852625619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8586544502852625619'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/04/fglrx-sur-debian-encore-des-histoires.html' title='Fglrx sur Debian - Encore des histoires'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-3300550676952423061</id><published>2011-04-06T23:56:00.003+02:00</published><updated>2011-04-07T00:17:20.743+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ocaml'/><category scheme='http://www.blogger.com/atom/ns#' term='postgres'/><title type='text'>Postgresql et Ocaml: performances à l'insertion</title><content type='html'>Postgresql permet 2 types d'insertions: les insertions en pur SQL à l'aide d'un "insert", et les copies. À quel point les copies sont-elles plus efficaces que les insertions?&lt;br /&gt;&lt;br /&gt;Voici quelques tests rapides via le mode immédiat d'Ocaml, en passant par le wrappeur Postgres. Ouvrons tout d'abord une connexion.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ocaml -I /usr/lib/ocaml/postgresql/ -I /usr/lib/ocaml/threads&lt;br /&gt;# #load "unix.cma";;&lt;br /&gt;# #load "threads.cma";;&lt;br /&gt;# #load "bigarray.cma";;&lt;br /&gt;# #load "postgresql.cma";;&lt;br /&gt;# let connectionstring = "host=localhost dbname=Test";;&lt;br /&gt;# let c = new Postgresql.connection ~conninfo:connectionstring ();;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Voici quelques fonctions de base qui servent respectivement à créer une séquence de a à b, et à mesurer le temps pour exécuter une fonction donnée. Notez que "seq" est un peu alambiquée pour permettre la tail-recursion (et donc de demander des sequences de 1M d'éléments sans dépassement de pile).&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# let seq a b = &lt;br /&gt;   let rec do_seq a r = &lt;br /&gt;    if a &gt; b then r else do_seq (a + 1) (a::r) &lt;br /&gt;   in List.rev(do_seq a []);;&lt;br /&gt;# let time f e = &lt;br /&gt;   let t1 = Unix.gettimeofday() in f e; &lt;br /&gt;   let t2 = Unix.gettimeofday() in &lt;br /&gt;   t2 -. t1;;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Et enfin, les deux fonctions à tester, l'une faisant tourner n insertions dans une transaction, l'autre utilisant la copie.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# let run n = &lt;br /&gt;   ignore(c#exec "begin"); &lt;br /&gt;   List.iter &lt;br /&gt;    (fun e -&gt; ignore(c#exec  &lt;br /&gt;                     ~params:[|string_of_int e; "def"; "0.143"|] &lt;br /&gt;                     "insert into data values($1, $2, $3)")) &lt;br /&gt;    (seq 1 n); &lt;br /&gt;   ignore(c#exec "commit");;&lt;br /&gt;# let batch n = &lt;br /&gt;   ignore(c#exec "copy data from stdin"); &lt;br /&gt;   List.iter &lt;br /&gt;    (fun e -&gt; ignore(c#putline ((string_of_int e)^"\tdef\t0.143\n"))) &lt;br /&gt;    (seq 1 n); &lt;br /&gt;   ignore c#endcopy;;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ces fonctions font strictement la même chose, c'est à dire insérer pour i de 1 à n, {i, "def", 0.143} dans une table ayant pour colonnes un entier, une chaîne, et un double.&lt;br /&gt;&lt;br /&gt;L'on fait tourner...&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;# time run 100000;;&lt;br /&gt;- : float = 13.3781638145446777&lt;br /&gt;# time batch 100000;;&lt;br /&gt;- : float = 0.458184957504272461&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Ce qui nous donne un déjà très honorable 7500 insertions par seconde avec des insert, et un ahurissant 220000 insertions par seconde avec une copie. Les gains sont encore plus significatifs avec plus de lignes, la copie atteignant 240000 insertions par seconde pour 1 million d'éléments.&lt;br /&gt;&lt;br /&gt;Notez tout de même que ma base est configurée avec fsync = off afin d'éviter les coûteuses synchronisations avec le disque. Quand bien même il est vrai qu'attendre que tout soit écrit aplanirait les différences, un cas d'utilisation standard d'insertions massives est la jointure avec une table temporaire pour faire un select, par exemple, pour lequel les écritures disques ne rentreront pas en compte.&lt;br /&gt;&lt;br /&gt;Ce qui nous fait donc quand même une insertion par copie 30 fois plus rapide qu'une insertion en SQL pur.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-3300550676952423061?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/3300550676952423061/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=3300550676952423061' title='2 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3300550676952423061'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3300550676952423061'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/04/postgresql-et-ocaml-performances.html' title='Postgresql et Ocaml: performances à l&apos;insertion'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-8309990129404260851</id><published>2011-04-05T00:01:00.004+02:00</published><updated>2011-04-05T00:32:36.982+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>stream iterators</title><content type='html'>C'est un équilibre, il me faut ma dose de code. Et vu que j'en ai en quantités industrielles au boulot, j'ai plutôt tendance à me rattraper sur mes lectures une fois réintégré mon trou. Cependant, ce n'est pas une raison pour se laisser totalement abattre, et je me suis dit que j'allais mentionner une fonctionnalité que je me suis mis à utiliser récemment: les stream iterators. À ma grande honte, je dois admettre que j'en ai compris l'utilité en notant un exercice d'un candidat lors d'une de nos sessions de recrutement. L'ensemble était moyen, mais sa manière de lire les fichiers de données était tout à fait remarquable.&lt;br /&gt;&lt;br /&gt;Exercice classique: étant donné un fichier contenant une liste d'entiers, les mettre dans un vecteur, et les afficher à l'écran.&lt;br /&gt;&lt;br /&gt;Les solutions habituelles vont du plus manuel à coup de buffers et de recherche d'espaces, ou de caractères non numériques, à des choses plus propres de type boucles avec des ifstream. Sans parler des soucis à la fin du fichier, pour savoir quand s'arrêter, comment supporter un retour chariot final ou pas...&lt;br /&gt;&lt;br /&gt;Avec les istream_iterator, c'est un plaisir: comme leur nom l'indique, on leur donne un istream, et on itère.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;fstream&amp;gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;#include &amp;lt;iterator&amp;gt;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  std::vector&amp;lt;int&amp;gt; myNumbers;&lt;br /&gt;&lt;br /&gt;  std::ifstream f("myfile.txt");&lt;br /&gt;  std::copy(std::istream_iterator&amp;lt;int&amp;gt;(f),&lt;br /&gt;            std::istream_iterator&amp;lt;int&amp;gt;(),&lt;br /&gt;            std::back_inserter(myNumbers));&lt;br /&gt;  &lt;br /&gt;  std::for_each(myNumbers.begin(),&lt;br /&gt;                myNumbers.end(),&lt;br /&gt;                [](int i){std::cout &amp;lt;&amp;lt; i &amp;lt;&amp;lt; "\n";});&lt;br /&gt;  std::cout.flush();&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Et le résultat:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;$ cat myfile.txt &lt;br /&gt;1 123 33 2222 1425&lt;br /&gt;78&lt;br /&gt;11&lt;br /&gt;&lt;br /&gt;$ ./test&lt;br /&gt;1&lt;br /&gt;123&lt;br /&gt;33&lt;br /&gt;2222&lt;br /&gt;1425&lt;br /&gt;78&lt;br /&gt;11&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;J'avoue, je n'ai pas pu m'empêcher de coller une lambda. On ne se refait pas.&lt;br /&gt;&lt;br /&gt;Alors certes, ce n'est que de l'encapsulation de fonctionnalités de base. Mais c'est pour moi le bon idiome pour ce genre d'activités, et j'aimerais voir plus de code se baser dessus, et moins sur des solutions à la mimine et trop souvent buggées.&lt;br /&gt;&lt;br /&gt;La beauté de la chose apparaît complétement lorsque l'on se rend compte qu'on peut passer n'importe quel objet streamable en paramètre template. Créez votre objet, son opérateur de stream, et basta, lisez-en des listes et des listes.&lt;br /&gt;&lt;br /&gt;Dernière remarque, un poil hors sujet: je crois que la beauté des stream et de la hiérarchie de classe associée n'apparaît vraiment que le jour où vous devez faire un test unitaire d'une horreur prenant un FILE *. Le triptyque istream pour la classe générique, istringstream pour les tests unitaires et ifstream pour la production resplendit au firmament de l'ingénierie logicielle.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-8309990129404260851?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/8309990129404260851/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=8309990129404260851' title='2 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8309990129404260851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8309990129404260851'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/04/stream-iterators.html' title='stream iterators'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-1117387139561062350</id><published>2011-03-22T22:49:00.003+01:00</published><updated>2011-03-22T23:09:14.522+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Être consistent...</title><content type='html'>Rhaaa, IBM! Ils viennent de confirmer après 3 jours d'arrachage de cheveux qu'ils ne supportent pas une fonctionnalité qui semble pourtant basique.&lt;br /&gt;&lt;br /&gt;DB2, ou plutôt son API C, répondant au doux nom de CLI, fournit un mode très efficace exécuter plusieurs fois une même requête. L'idée est de créer un tableau, de "binder" ce tableau à une colonne (via un appel à SQLBindParameter), puis d'exécuter la requête préparée. Tout est envoyé en une fois à la base, ce qui évite l'effet ping-pong entre le client et le serveur. Par exemple, une requête "insert into mytable values(?)" permet d'insérer des milliers de lignes en un seul appel.&lt;br /&gt;&lt;br /&gt;Nous codons donc une belle couche d'abstraction en C++, et continuons joyeusement à coder. &lt;br /&gt;&lt;br /&gt;Jusqu'au jour où je découvre que le binding par colonnes ne fonctionne pas avec les procédures stockées. Dans le genre, je créé une procédure qui fait un bête insert dans mytable, et j'appelle "call myproc(?)". Pire, DB2 va exécuter la procédure, mais seulement sur le premier élément, ce qui cause un beau bordel dans la base. La documentation est peu claire sur ce point précis, la spec ODBC dit que ça devrait marcher. Eh ben non.&lt;br /&gt;&lt;br /&gt;Reprenons: Une fonctionnalité qui semble pourtant aller de soi manque, ce manquement est mal documenté, et au lieu d'envoyer un message d'erreur clair, seule une partie de la requête tourne, causant une corruption des données. Peut-être que la raison fondamentale est que insert, update et delete supportent un vrai mode d'insertion par tableau, mais dans ce cas pourquoi ne pas au moins tenter d'être consistent, et pour le moteur de base de données de revenir dans un mode ligne par ligne dans le cas des procédures stockées? J'ai du mal à penser qu'IBM n'a pas les moyens humains de fournir quelque chose qui semble aussi trivial.&lt;br /&gt;&lt;br /&gt;La solution, c'est d'utiliser le binding par valeur pour toute requête contenant une procédure stockée, mais c'est difficile à abstraire, puisqu'il faut soit laisser à l'utilisateur le choix (et donc la chance de se tromper), soit tenter d'analyser la requête pour détecter si elle est optimisable. En l'occurence, j'ai choisi la sale mais raisonnablement triviale solution d'optimiser si le premier mot de la requête est "insert". Et le code de la couche d'abstraction devient plus moche car il doit supporter deux types de bindings, et donc deux chemins de code, avec les presque duplications et l'augmentation des risques de se bugs qui vont avec. Beurk.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-1117387139561062350?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/1117387139561062350/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=1117387139561062350' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1117387139561062350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1117387139561062350'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/03/etre-consistent.html' title='Être consistent...'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4799005344290910489</id><published>2011-03-13T12:26:00.002+01:00</published><updated>2011-03-13T13:30:59.739+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>g++ 4.5 et C++0x - Les nouveautés</title><content type='html'>J'ai porté Openrailz sous g++4.5, ce qui me permet d'utiliser plus de fonctionnalités de C++0x, mais a également soulevé quelque problèmes inattendus. Petit topo.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Destructeur virtuel et &lt;i&gt;= default&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Tout d'abord, les mauvaises nouvelles. Je ne sais si vous avez déjà souffert du problème, mais je n'ai jamais trouvé une manière complétement satisfaisante d'implémenter le destructeur virtuel en écrivant une interface. L'on peut inliner le code:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Miaou&lt;br /&gt;{&lt;br /&gt;  virtual ~Miaou() {}&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;mais c'est moche. L'on peut mettre le code en dessous:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Miaou&lt;br /&gt;{&lt;br /&gt;  virtual ~Miaou();&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;inline Miaou::~Miaou()&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;mais c'est encore plus moche, sans compter la verbosité lorsque la déclaration est un peu plus complexe (gros template, par exemple). Enfin, l'on peut juste mettre la déclaration dans son .cpp, mais on se retrouve avec un .cpp qui ne contient qu'une déclaration vide, et toujours aussi potentiellement verbeuse.&lt;br /&gt;&lt;br /&gt;Lorsque j'ai découvert le &lt;i&gt;= default&lt;/i&gt; de C++0x, je me suis dit, bonne nouvelle, voilà enfin comment résoudre le problème:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Miaou&lt;br /&gt;{&lt;br /&gt;  virtual ~Miaou() = default;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;C'est joli, moderne, et ça fait exactement ce que ça dit. Malheureusement, c'est également interdit par le standard, et si g++4.4 laissait passer, g++4.5 le bloque. Le standard interdit en effet de déclarer un destructeur virtuel par défaut à la première déclaration. C'est à dire que pour écrire du code correct, il faut faire:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Miaou&lt;br /&gt;{&lt;br /&gt;  virtual ~Miaou();&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;inline Miaou::~Miaou() = default;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ce qui est tout aussi moche. Retour donc a la case départ.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Strict aliasing rules et boost::optional&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;J'avais commencé à virer les boost::optional de ma codebase, car ils causaient un ennuyeux warning dans g++4.4: &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;boost/optional.hpp&amp;gt;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  boost::optional&amp;lt;int&amp;gt; b;&lt;br /&gt;  if(b)&lt;br /&gt;  {&lt;br /&gt;    std::cout &amp;lt;&amp;lt; *b &amp;lt;&amp;lt; std::endl;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;La compilation avec g++4.4 renvoie ce message:&lt;br /&gt;&lt;br /&gt;optional.cpp: In function ‘int main()’:&lt;br /&gt;optional.cpp:10: warning: dereferencing pointer ‘&lt;anonymous&gt;’ does break strict-aliasing rules&lt;br /&gt;optional.cpp:10: note: initialized from here&lt;br /&gt;&lt;br /&gt;Alors, bien sûr, l'on peut utiliser le flag -fno-strict-aliasing, mais l'on réduit les performances.&lt;br /&gt;&lt;br /&gt;Les discussions sont allé bon train sur les mailing-lists de Boost, mais il semblerait que le code soit en fait bon, et qu'il s'agisse d'un &lt;a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41874"&gt;bug de g++4.4&lt;/a&gt;. G++4.5 ne se plaint pas sur ce code, et je compte donc bien le réintégrer vite fait, en particulier pour gérer les colonnes nullables dans mon code de base de données (voir le &lt;a href="http://aubedesheros.blogspot.com/2011/03/variadic-templates-et-pqxx.html"&gt;post précédent&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Et bien sûr... Les lambdas!&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Va falloir commencer à s'habituer aux listes de captures, et faire gaffe au passage par valeur / référence. Raison de plus pour commencer le plus tôt possible, et en coller partout. 'tention les yeux! Notons également des améliorations sur les variadic templates, et les chaînes de caractères unicode.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4799005344290910489?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4799005344290910489/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4799005344290910489' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4799005344290910489'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4799005344290910489'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/03/g-45-et-c0x-les-nouveautes.html' title='g++ 4.5 et C++0x - Les nouveautés'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-2017980291369021710</id><published>2011-03-12T17:34:00.003+01:00</published><updated>2011-03-12T17:51:36.971+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='postgres'/><title type='text'>Variadic Templates et pqxx</title><content type='html'>Je me suis lancé de nouveau dans l'utilisation des variadic templates pour simplifier (!) les appels à la base de données. La chose est un poil touffue, et compile avec g++4.5. Tout d'abord,un exemple d'utilisation: on créé un type &lt;i&gt;Query&lt;/i&gt; avec les types des paramètres d'entrée et de sortie en paramètres template. L'on peut ensuite faire tourner la requête avec &lt;i&gt;execute&lt;/i&gt;, lequel prend les paramètres d'entrée fortement typés. Ensuite, un itérateur permet de récupérer les résultats sous forme de &lt;i&gt;std::tuple&lt;/i&gt;.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;typedef &lt;br /&gt;  db::Query&amp;lt;db::ParamSet&amp;lt;std::string, std::string&amp;gt;, &lt;br /&gt;            db::ResultSet&amp;lt;std::string, std::string&amp;gt; &amp;gt;&lt;br /&gt;  QueryT;&lt;br /&gt;QueryT query(dbConn, "select $2::text, $1::text");  &lt;br /&gt;query.execute("abc", "def");&lt;br /&gt;&lt;br /&gt;for_each(query.begin(),&lt;br /&gt;         query.end(),&lt;br /&gt;         [](const QueryT::ResultType &amp;amp; result)&lt;br /&gt;         {&lt;br /&gt;           std::cout &amp;lt;&amp;lt; std::get&amp;lt;0&amp;gt;(result) &amp;lt;&amp;lt; "\t" &lt;br /&gt;                     &amp;lt;&amp;lt; std::get&amp;lt;1&amp;gt;(result) &amp;lt;&amp;lt; std::endl;&lt;br /&gt;         });&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Et pour ceux que ça intéresse, le code derrière tout ça. Il ne supporte pour l'instant que les chaînes de caractères en entrée, je laisse de côté le long et ennuyeux code pour gérer d'autres types (basé sur les Traits). Le principe est un peu toujours le même: dérouler le variadic template à l'aide de classes récursives partiellement spécialisées. Notez que le ResultSet est instancié, bien que n'ayant pas d'attributs. Lassé de me battre avec le compilo qui ne comprenait pas mes appels de méthodes statiques, j'ai instancié tout ça.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;namespace db&lt;br /&gt;{&lt;br /&gt;  template &amp;lt;typename ... Args&amp;gt;&lt;br /&gt;  class ParamSet;&lt;br /&gt;  &lt;br /&gt;  template&amp;lt;&amp;gt;&lt;br /&gt;  class ParamSet&amp;lt;&amp;gt;&lt;br /&gt;  {&lt;br /&gt;  public:&lt;br /&gt;    void prepare(const pqxx::prepare::declaration &amp;amp;)&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    pqxx::prepare::invocation &amp;amp; execute(pqxx::prepare::invocation &amp;amp; invocation)&lt;br /&gt;    {&lt;br /&gt;      return invocation;&lt;br /&gt;    }&lt;br /&gt;  };&lt;br /&gt;  &lt;br /&gt;  template &amp;lt;typename T, typename ... Args&amp;gt;&lt;br /&gt;  class ParamSet&amp;lt;T, Args...&amp;gt;&lt;br /&gt;  {&lt;br /&gt;  public:&lt;br /&gt;    void prepare(const pqxx::prepare::declaration &amp;amp; declaration)&lt;br /&gt;    {&lt;br /&gt;      m_sub.prepare(declaration("text", pqxx::prepare::treat_string));&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    pqxx::prepare::invocation &amp;amp; execute(pqxx::prepare::invocation &amp;amp; invocation, &lt;br /&gt;                                        const T &amp;amp; data, &lt;br /&gt;                                        Args... others)&lt;br /&gt;    {&lt;br /&gt;      return m_sub.execute(invocation(data), others...);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;  private:&lt;br /&gt;    ParamSet&amp;lt;Args...&amp;gt; m_sub;&lt;br /&gt;  };&lt;br /&gt;  &lt;br /&gt;  template&amp;lt;typename ... Args&amp;gt;&lt;br /&gt;  class ResultSet;&lt;br /&gt;&lt;br /&gt;  template&amp;lt;&amp;gt;&lt;br /&gt;  class ResultSet&amp;lt;&amp;gt;&lt;br /&gt;  {&lt;br /&gt;  public:&lt;br /&gt;    template&amp;lt;size_t N, typename TUPLE&amp;gt;&lt;br /&gt;    void doPopulate(const pqxx::result::tuple::const_iterator &amp;amp;, TUPLE &amp;amp;)&lt;br /&gt;    {&lt;br /&gt;    }    &lt;br /&gt;  };&lt;br /&gt;  &lt;br /&gt;  template&amp;lt;typename T, typename ... Args&amp;gt;&lt;br /&gt;  class ResultSet&amp;lt;T, Args...&amp;gt;&lt;br /&gt;  {&lt;br /&gt;  public:&lt;br /&gt;    typedef std::tuple&amp;lt;T, Args...&amp;gt; TupleT;&lt;br /&gt;    &lt;br /&gt;    void populate(const pqxx::result::tuple &amp;amp; input, TupleT &amp;amp; output)&lt;br /&gt;    {&lt;br /&gt;      doPopulate&amp;lt;0&amp;gt;(input.begin(), output);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    template&amp;lt;size_t N, typename TUPLE&amp;gt;&lt;br /&gt;    void doPopulate(const pqxx::result::tuple::const_iterator &amp;amp; it, TUPLE &amp;amp; output)&lt;br /&gt;    {&lt;br /&gt;      std::get&amp;lt;N&amp;gt;(output) = it-&amp;gt;as&amp;lt;T&amp;gt;();&lt;br /&gt;      m_sub.doPopulate&amp;lt;N + 1&amp;gt;(it + 1, output);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;  private:&lt;br /&gt;    ResultSet&amp;lt;Args...&amp;gt; m_sub;&lt;br /&gt;  };&lt;br /&gt;  &lt;br /&gt;  template&amp;lt;typename PARAMSET, typename RESULTSET&amp;gt;&lt;br /&gt;  class Query&lt;br /&gt;  {&lt;br /&gt;  public:&lt;br /&gt;    Query(const std::shared_ptr&amp;lt;pqxx::connection&amp;gt; &amp;amp; dbConn, &lt;br /&gt;          const std::string &amp;amp; sql):&lt;br /&gt;      m_dbConn(dbConn),&lt;br /&gt;      m_sql(sql)&lt;br /&gt;    {&lt;br /&gt;      m_paramSet.prepare(m_dbConn-&amp;gt;prepare(sql, sql));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    template&amp;lt;typename ... Args&amp;gt;&lt;br /&gt;    void execute(Args... args)&lt;br /&gt;    {&lt;br /&gt;      pqxx::work transaction(*m_dbConn, "Transaction");&lt;br /&gt;      pqxx::prepare::invocation invocation = &lt;br /&gt;        transaction.prepared(m_sql);&lt;br /&gt;      &lt;br /&gt;      pqxx::result result = m_paramSet.execute(invocation, args...).exec();&lt;br /&gt;      m_result.resize(result.size());&lt;br /&gt;      &lt;br /&gt;      auto it = result.begin();&lt;br /&gt;      auto end = result.end();&lt;br /&gt;      auto it_r = m_result.begin();&lt;br /&gt;&lt;br /&gt;      for(; it != end; ++it, ++it_r)&lt;br /&gt;      {&lt;br /&gt;        m_resultSet.populate(*it, *it_r);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    size_t size() const&lt;br /&gt;    {&lt;br /&gt;      return m_result.size();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    typedef typename RESULTSET::TupleT ResultType;&lt;br /&gt;    typedef typename std::vector&amp;lt;typename RESULTSET::TupleT&amp;gt;::const_iterator &lt;br /&gt;      const_iterator;&lt;br /&gt;    &lt;br /&gt;    const_iterator begin()&lt;br /&gt;    {&lt;br /&gt;      return m_result.begin();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    const_iterator end()&lt;br /&gt;    {&lt;br /&gt;      return m_result.end();&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;  private:&lt;br /&gt;    std::shared_ptr&amp;lt;pqxx::connection&amp;gt; m_dbConn;&lt;br /&gt;    std::string m_sql;&lt;br /&gt;    PARAMSET m_paramSet;&lt;br /&gt;    RESULTSET m_resultSet;&lt;br /&gt;    std::vector&amp;lt;typename RESULTSET::TupleT&amp;gt; m_result;&lt;br /&gt;  };&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-2017980291369021710?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/2017980291369021710/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=2017980291369021710' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2017980291369021710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/2017980291369021710'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/03/variadic-templates-et-pqxx.html' title='Variadic Templates et pqxx'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-7067041948832889787</id><published>2011-03-06T13:28:00.003+01:00</published><updated>2011-03-06T14:03:48.675+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debian'/><category scheme='http://www.blogger.com/atom/ns#' term='postgres'/><title type='text'>GnuCash 2.4.2 débarque sur Debian Wheezy</title><content type='html'>Enfin, les paquets intéressants débarquent dans Debian Testing. Je fais mes comptes depuis plus d'un an déjà (essayez au moins une fois quelques mois pour voir, c'est très intéressant!), j'utilise GnuCash et j'en suis fort satisfait. Peut-être moins joli que Grisbi et KMyMoney, mais il fait le boulot, et c'est le principal.&lt;br /&gt;&lt;br /&gt;La fonctionnalité la plus intéressante de cette nouvelle release est la possibilité d'utiliser une base de données au lieu de fichiers XML. Voici donc la marche à suivre pour bouger sur Postgresql.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Tout d'abord, assurez-vous que Postgres est installé, avec un compte qui marche et les permissions qui vont bien&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Installez le paquet &lt;b&gt;libdbd-pgsql&lt;/b&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Créez la base gnucash avec la commande suivante: &lt;b&gt;createdb gnucash&lt;/b&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Démarrez gnucash, et ouvrez votre fichier de compte&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Allez dans File -&gt; Save as, et choisissez "postgres" dans la section "data format". La fenêtre change, et vous demande vos identifiants de connexion. Entrez le login (et le mot de passe si vous en avez un), zappez le baratin  de Gnome-Keyring (OK à tout (sauf si vous êtes un accro de sa sécurité)), et basta!&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Les plus curieux d'entre vous pourront aller jeter un coup d'œil à la base, et admirer les tables &lt;i&gt;accounts&lt;/i&gt;, &lt;i&gt;transactions&lt;/i&gt; et &lt;i&gt;splits&lt;/i&gt; qui contiennent l'essentiel des données intéressantes.&lt;br /&gt;&lt;br /&gt;En dehors de faire son geek, passer à un backend sur base de données est pratique par exemple si l'on a déjà des systèmes de sauvegarde tournant sur la base. Et c'est toujours ça de moins à penser lors d'une migration sur une autre machine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-7067041948832889787?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/7067041948832889787/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=7067041948832889787' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7067041948832889787'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7067041948832889787'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/03/gnucash-242-debarque-sur-debian-wheezy.html' title='GnuCash 2.4.2 débarque sur Debian Wheezy'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4707055472307631971</id><published>2011-03-04T23:26:00.003+01:00</published><updated>2011-03-04T23:46:19.378+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Ais-je rêvé? Pas de boost::mutex::is_locked!</title><content type='html'>Je l'aurais pourtant juré (et j'ai eu l'air bête au boulot à cause de ça), mais contrairement à ce que je croyais et malgré ma certitude que je l'avait déjà utilisée, les &lt;i&gt;{boost,std}::mutex&lt;/i&gt; n'ont pas de méthode &lt;i&gt;is_locked&lt;/i&gt; qui permettrait de savoir si le mutex est acquis ou pas.&lt;br /&gt;&lt;br /&gt;Dès que je mentionne cette fonctionnalité, l'on me regarde avec des grands yeux: "Mais pourquoi voudrais-tu faire ça? Si tu en as besoin, c'est que ton design est pourri / que tu ne sais pas utiliser les mutex / que tu est bête" (rayer la mention inutile). Alors, oui, je comprends bien que la plupart des utilisations d'une telle méthode sont des aberrations. Mais voilà mon cas d'utilisation:&lt;br /&gt;&lt;br /&gt;Imaginez que vous avez une belle classe, gentiment thread-safe (et Wikipédia peut aller se rhabiller avec son "à fil sécurisé", non mais...), et donc possédant un beau mutex (privé, mutable, un beau mutex, quoi). Les méthodes publiques acquièrent le mutex, et appellent des méthodes privées qui s'attendent donc à ce que le mutex soit déjà pris, ce qui est donc une précondition. Afin que le prochain gus écrivant sa méthode publique dans ma classe ne casse tout, j'aimerais beaucoup pouvoir effectivement vérifier cette précondition, avec par exemple un &lt;i&gt;assert(m_mutex.is_locked())&lt;/i&gt;. Si mon gus oublie d'acquérir le verrou, il aura une belle assertion lors de ses tests unitaires (encore faut-il qu'il écrive des tests unitaires, mais c'est un autre débat).&lt;br /&gt;&lt;br /&gt;Et la, généralement, mon interlocuteur change d'avis: "Tiens, c'est vrai, ça serait pratique...". &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Les solutions&lt;/b&gt;&lt;br /&gt;Car elles existent.&lt;br /&gt;&lt;br /&gt;Une possibilité est pour chaque méthode privée s'attendant à être protégée de prendre en arguments un lock (et pas un mutex), inutilisé dans le corps de la méthode. C'est une sorte de rappel, l'appelant de la fonction devant obligatoirement créer un objet lock. Bien sûr, l'on peut le contourner en créant un objet lock vide, ou qui acquiert un autre mutex, ou qui appelle &lt;i&gt;unlock&lt;/i&gt; avant de passer l'objet, mais bon, il faut vraiment être pervers. Autre iconvénient: c'est assez moche, car ça bave dans l'interface.&lt;br /&gt;&lt;br /&gt;Une autre possibilité est d'écrire la méthode &lt;i&gt;is_locked&lt;/i&gt;, en tentant d'acquérir à nouveau le verrou avec un try_lock, et en vérifiant le résultat. Ce n'est pas spécialement efficace, mais dans une assertion virée des builds optimisés, ce n'est probablement pas un problème. Inconvénient: cela ne marche que si le mutex est non récursif. Sinon, c'est cassé.&lt;br /&gt;&lt;br /&gt;Décevant.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4707055472307631971?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4707055472307631971/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4707055472307631971' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4707055472307631971'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4707055472307631971'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/03/ais-je-reve-pas-de-boostmutexislocked.html' title='Ais-je rêvé? Pas de boost::mutex::is_locked!'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-37133114902772447</id><published>2011-02-18T21:13:00.004+01:00</published><updated>2011-02-18T21:22:04.356+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='monde'/><title type='text'>Brain overload</title><content type='html'>Entre d'épineux problèmes de design au boulot, et d'épineux problèmes de design sur OpenRailz, on ne peut pas dire que je code beaucoup, à mon grand regret. &lt;br /&gt;&lt;br /&gt;C'est que maintenant qu'OpenRailz permet de créer des gares, des rails, des trains, et d'assigner des itinéraires, il est temps de commencer à créer de vraies villes. Pour ce faire, je pense pour l'instant à effectuer un pavage du plan à l'aide de polygones, pour en faire des routes et des zones constructibles. Il serait probablement raisonnablement aisé de créer ainsi une ville complétement procédurale, mais je me heurte cependant aux difficultés d'interface: comment fournir au joueur les outils pour créer ses routes, sans affoler le générateur de ville, et sans causer des mini-trous moches au niveau du pavage?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-37133114902772447?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/37133114902772447/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=37133114902772447' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/37133114902772447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/37133114902772447'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/02/brain-overload.html' title='Brain overload'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4991956491706422765</id><published>2011-02-12T15:53:00.003+01:00</published><updated>2011-02-12T16:08:41.604+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debian'/><category scheme='http://www.blogger.com/atom/ns#' term='postgres'/><title type='text'>Postgresql 9.0 chez Debian!</title><content type='html'>Bonne surprise lors de mon &lt;i&gt;aptitude update; aptitude dist-upgrade&lt;/i&gt; hebdomadaire (j'aime bien être à jour), les paquets Postgres 9.0 viennent d'atterrir dans Testing. Cela m'a permis de découvrir les outils de mise à jour, qui sont plutôt efficaces.&lt;br /&gt;&lt;br /&gt;Par coup de bol, le passage du méta-paquet postgresql de 8.4 à 9.0 ne m'a pas proposé de virer 8.4, puisque j'avais postgis qui en dépendait. Si ce n'est pas votre cas et que la mise à jour vous propose de supprimer 8.4, annulez, et forcez le paquet 8.4 en manuel (m dans aptitude). Maintenant, laisser l'installation ajouter 9.0 sur un autre port.&lt;br /&gt;&lt;br /&gt;C'est là que tout devient simple: passez root, et tapez:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;pg_dropcluster --stop 9.0 main&lt;/i&gt;&lt;br /&gt;&lt;i&gt;pg_upgradecluster 8.4 main&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Le nouveau cluster créé par l'installeur Debian est oblitéré, un nouveau cluster est créé, et les bases migrées dessus, et les ports inversés. Une fois ce processus terminé, vérifiez vos bases (et peut-être redémarrer certains services, chez moi Ocsigen s'est fait dessus lors du changement), puis, quand vous êtes contents,&lt;br /&gt;&lt;br /&gt;&lt;i&gt;pg_dropcluster 8.4 main&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Un peu de nettoyage dans aptitude pour virer tout ce qui est 8.4, et basta!&lt;br /&gt;&lt;br /&gt;&lt;font color=#ff0000&gt;'tention cependant!&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;Toutes les dépendances ne sont pas encore arrivées: postgis est encore en 8.4, et pgadmin foire méchamment. Quand bien même les paquets qui vont bien devraient débarquer incessamment sous peu, si vous faites quoi que ce soit d'important avec votre base, peut-être est-il plus sage d'attendre un poil.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4991956491706422765?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4991956491706422765/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4991956491706422765' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4991956491706422765'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4991956491706422765'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/02/postgresql-90-chez-debian.html' title='Postgresql 9.0 chez Debian!'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-1081269805235456639</id><published>2011-02-10T20:49:00.001+01:00</published><updated>2011-02-10T20:51:25.530+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>La vraie brochette d'iguane de Fallout</title><content type='html'>J'ai découvert dans les rues de Hong Kong la fameuse brochette d'iguane de Fallout!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-2x-CCzwY7Lw/TVRBpf00ZSI/AAAAAAAAEZ8/01eUeST70vw/s1600/iguana_on_a_stick.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://4.bp.blogspot.com/-2x-CCzwY7Lw/TVRBpf00ZSI/AAAAAAAAEZ8/01eUeST70vw/s320/iguana_on_a_stick.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5572150820137624866" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-1081269805235456639?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/1081269805235456639/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=1081269805235456639' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1081269805235456639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1081269805235456639'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/02/la-vraie-brochette-diguane-de-fallout.html' title='La vraie brochette d&apos;iguane de Fallout'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-2x-CCzwY7Lw/TVRBpf00ZSI/AAAAAAAAEZ8/01eUeST70vw/s72-c/iguana_on_a_stick.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-7281518462707207878</id><published>2011-01-23T19:29:00.005+01:00</published><updated>2011-01-23T19:32:15.134+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='client'/><title type='text'>Itinéraires</title><content type='html'>Le nouveau système d'itinéraires est en grande partie implémentée. Il est maintenant possible de donner une liste d'ordres à son train, et de l'observer allant d'une gare à une autre. Il est également possible d'arrêter et de redémarrer son train en route.&lt;br /&gt;&lt;br /&gt;Ce sera évidemment bien plus joli avec des noms de gares plutôt que des numéros.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_c7c8R8g7is8/TTxz5acBb1I/AAAAAAAAEZU/RD-GSjK1GYk/s1600/openrailz_controle.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 246px;" src="http://1.bp.blogspot.com/_c7c8R8g7is8/TTxz5acBb1I/AAAAAAAAEZU/RD-GSjK1GYk/s320/openrailz_controle.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5565450669709684562" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-7281518462707207878?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/7281518462707207878/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=7281518462707207878' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7281518462707207878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7281518462707207878'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/01/itineraires.html' title='Itinéraires'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_c7c8R8g7is8/TTxz5acBb1I/AAAAAAAAEZU/RD-GSjK1GYk/s72-c/openrailz_controle.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-395918732352889175</id><published>2011-01-22T23:54:00.002+01:00</published><updated>2011-01-22T23:57:32.982+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='client'/><title type='text'>La GUI se met à jour</title><content type='html'>Mon observer (nommé RWData) fonctionne comme prévu. J'en ai profité pour revoir un petit peu les interfaces de propriétés. Pour les trains, donc, nous avons la vitesse courante, qui se met à jour au fur et à mesure, et la boite qui contiendra bientôt l'itinéraire.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_c7c8R8g7is8/TTtgbiHRi_I/AAAAAAAAEZM/18nmY9fne-E/s1600/openrailz_vitesse.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 166px;" src="http://1.bp.blogspot.com/_c7c8R8g7is8/TTtgbiHRi_I/AAAAAAAAEZM/18nmY9fne-E/s320/openrailz_vitesse.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5565147790676429810" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-395918732352889175?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/395918732352889175/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=395918732352889175' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/395918732352889175'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/395918732352889175'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/01/la-gui-se-met-jour.html' title='La GUI se met à jour'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_c7c8R8g7is8/TTtgbiHRi_I/AAAAAAAAEZM/18nmY9fne-E/s72-c/openrailz_vitesse.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-8487529969034130478</id><published>2011-01-22T14:50:00.003+01:00</published><updated>2011-01-22T15:18:32.366+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><category scheme='http://www.blogger.com/atom/ns#' term='mmorpg'/><title type='text'>Des nouvelles d'Infinity</title><content type='html'>Comme mentionné &lt;a href="http://aubedesheros.blogspot.com/2010/05/les-nouveautes-dans-le-monde.html"&gt;dans un post précédent&lt;/a&gt;, je surveille de près le projet &lt;a href="http://www.infinity-universe.com/Infinity/index.php"&gt;Infinity&lt;/a&gt;, l'ambitieux projet de MMORPG spatial amateur (ou plutôt semi-pro, comme on le verra dans la suite du post). Hier, son concepteur a publié sa rétrospective pour 2010, et a notamment annoncé un changement majeur sur la conduite du projet: maintenant secondé par un développeur pro, il a monté une entreprise, I-novae studios, et se concentre sur la vente du moteur de jeu. &lt;br /&gt;&lt;br /&gt;Ceci a bien entendu causé quelques changements dans ses priorités, et il semble que beaucoup de temps ait été passé sur les bug fix, le port vers d'autres architectures, l'intégration à .NET, et bien évidemment l'effort marketing. Le jeu Infinity en lui-même n'est pas abandonné, mais mis de côté en attendant que la vente du moteur permette au studio de recruter une véritable équipe de développement.&lt;br /&gt;&lt;br /&gt;La communauté est très divisée par ces nouvelles. Tout en admettant que la vente du moteur est la chose à faire pour lever des fonds, l'inévitable recul de la date de publication du jeu Infinity est difficilement vécue par ceux qui espéraient que le silence de ces derniers mois débouche sur une béta jouable.&lt;br /&gt;&lt;br /&gt;Tous les fans d'Infinity (et j'en suis!) devront donc continuer de prendre leur mal en patience, et d'espérer un rapide succès commercial du moteur. Plus personnellement, j'espère tout de même que nous aurons au moins quelques vidéos à se mettre sous la dent.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-8487529969034130478?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/8487529969034130478/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=8487529969034130478' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8487529969034130478'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8487529969034130478'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/01/des-nouvelles-dinfinity.html' title='Des nouvelles d&apos;Infinity'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4341246085251345735</id><published>2011-01-22T14:31:00.002+01:00</published><updated>2011-01-22T14:43:08.990+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><category scheme='http://www.blogger.com/atom/ns#' term='projet'/><title type='text'>20 000 lignes</title><content type='html'>Voilà, c'est atteint, le projet fait maintenant très exactement 20032 lignes de code, avec l'ajout hier soir d'une implémentation générique d'un &lt;a href="http://fr.wikipedia.org/wiki/Observateur_%28patron_de_conception%29"&gt;observer&lt;/a&gt; (on dit vraiment "patron de conception" pour design pattern???). Je vous en causerai plus avant après nettoyage du code.&lt;br /&gt;&lt;br /&gt;Mais, pour en revenir à nos lignes, je pense être plutôt dans une pente descendante: avec l'implémentation de piglet et la simplification annoncée du système d'itinéraires, c'est beaucoup de code qui va jarreter. Les systèmes de contrôle de version étant faits pour ça, j'ai la ferme intention d'oblitérer de vastes quantités de code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4341246085251345735?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4341246085251345735/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4341246085251345735' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4341246085251345735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4341246085251345735'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/01/20-000-lignes.html' title='20 000 lignes'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-7381545892053516290</id><published>2011-01-19T23:34:00.005+01:00</published><updated>2011-01-19T23:58:13.394+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='projet'/><category scheme='http://www.blogger.com/atom/ns#' term='client'/><title type='text'>Openrailz v0.2 sur Sourceforge</title><content type='html'>À la demande générale, j'ai publié sur Sourceforge &lt;a href="http://sourceforge.net/projects/adh/files/OpenRailz/v0.2/openrailz-v0.2-src.tar.bz2/download"&gt;la dernière version du code et des ressources d'OpenRailz&lt;/a&gt; dans un beau paquet. Pour Windows, malheureusement, il va falloir être un peu plus patients, et attendre que je trouve la motivation de porter le code.&lt;br /&gt;&lt;br /&gt;Pour ceux qui veulent tenter la compilation sous Linux, la difficulté va surtout dépendre de la disponibilités des bons paquets pour votre distribution préférée. Le fichier INSTALL explique comment compiler avec une Debian Squeeze, la seule subtilité étant qu'il faudra compiler soit-même wxWidgets 2.9 (pour l'antialiasing). Pour la compilation en elle-même, un bête &lt;i&gt;omake&lt;/i&gt; dans le répertoire principal fera l'affaire, mais il sera plus efficace de suivre d'un peu plus près la documentation, et d'utiliser les en-têtes précompilées ainsi que la compilation en parallèle.&lt;br /&gt;&lt;br /&gt;Les ressources sont fournies avec le code, et sont dans le répertoire "data". L'exécutable cherchant par défaut les données dans le répertoire courant, le mieux est de se placer dans le répertoire principal, et lancer OpenRailz en tapant &lt;i&gt;./debug/bin/openrailz&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;C'est là que tout se corse: je n'ai pu tester OpenRailz qu'avec ma carte vidéo, une Radeon HD 4870, en utilisant les drivers propriétaires, et j'ai peu de doutes que bien d'autres cartes ne supportent pas les shaders de la manière dont je les ai écrits. C'est vraiment au petit bonheur la chance. Les fichiers de shaders sont dans le répertoire &lt;i&gt;data/shader&lt;/i&gt;, et sont lus au runtime, donc vous pouvez tripatouiller un peu pour tenter de résoudre d'éventuels problèmes.&lt;br /&gt;&lt;br /&gt;Si, par le plus grand des hasards, OpenRailz se décidait à démarrer proprement, vous pourrez alors vous amuser un petit peu avec les circuits. &lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;La navigation se fait en maintenant le bouton droit pour l'orientation, et le bouton central pour les déplacements&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Ajoutez une gare, en sélectionnant l'icône "Build station", et en maintenant le bouton gauche à partir d'un endroit du terrain pour orienter le bâtiment&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Ajoutez quelques autres gares (backspace pour effacer la gare courante)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Passez en mode rails avec l'icône "Track layout". Les waypoints des gares apparaissent, en rouge car ils ne peuvent pas être manipulés&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Sélectionnez-en un, il devient doré. Puis cliquez et maintenez pour créer un autre waypoint. Une fois le bouton lâché, un rail apparaît si un chemin peut-être calculé. Re-cliquez et glissez pour réorienter un waypoint (manipulable, en vert) existant&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Le train courant est situé dans la première gare que vous avez créée. Passez en mode sélection avec l'icône "Selection tool", et cliquez sur une autre gare. S'il existe un chemin, le train va s'y déplacer!&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-7381545892053516290?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/7381545892053516290/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=7381545892053516290' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7381545892053516290'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7381545892053516290'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/01/openrailz-v02-sur-sourceforge.html' title='Openrailz v0.2 sur Sourceforge'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-7488275013838376356</id><published>2011-01-16T23:22:00.005+01:00</published><updated>2011-01-16T23:42:49.000+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='projet'/><title type='text'>Et maintenant?</title><content type='html'>Malgré quelques bugs, cette démo de déplacement des trains est une avancée majeure et valide le modèle d'entités graphiques (le bien nommé &lt;i&gt;piglet&lt;/i&gt;), le modèle de rails, et le pathfinder. La pose de rails, malheureusement, reste très ardue, mais ce sous-système est suffisamment générique pour être facilement amélioré plus tard, ce qui le rend non prioritaire.&lt;br /&gt;&lt;br /&gt;Je peux donc travailler sur l'amélioration du réalisme (accélérations et décélérations), l'interface (simplifier mon modèle d'itinéraires), et enfin m'attaquer à des améliorations de gameplay. Je pense notamment à enfin intégrer l'aspect passagers, avec des gares qui se remplissent de passagers désireux de voyager. L'aspect financier, avec le coût des gares, des rails et des trains, viendra plus tard.&lt;br /&gt;&lt;br /&gt;Mais peut-être avant tout ça faut il d'abord trouver enfin un modèle raisonnable pour les callbacks (fonctions de rappel, me dit Wikipedia (!)) entre le moteur et la GUI. L'approche monolithique consistant à faire dériver chaque élément de la GUI d'une interface qui fait tout (sélections de trains et de gares, changements de vitesse, itinéraires, passagers dans les gares, etc) est trop limitée: non seulement cette interface mammouth couplerait tous les composants, mais cela veut dire que des centaines de fois par seconde, chaque train va envoyer sa nouvelle vitesse, chaque gare va envoyer son nouveau nombre de passagers, et bien d'autres événements vont être générés et envoyés à des boites de dialogue qui vont pour la plupart les ignorer.&lt;br /&gt;&lt;br /&gt;Inspiré par une approche que j'ai vue au boulot (chut!), je vais tenter quelque chose de plus découplé: permettre à chaque composant de la GUI de s'enregistrer auprès d'un événement donné, en lui passant une fonction de callback, et gérer l'enregistrement dynamiquement au fur et à mesure des besoins de l'utilisateur. Ansi, l'utilisateur cliquant sur une gare, la boite de propriétés de la gare enregistre un callback directement sur un objet représentant le nombre de passagers. Lorsque ce nombre change, la boite de propriétés en est informée, et affiche la nouvelle valeur. Lorsque la gare est dé-sélectionnée, la boite de propriétés se dés-enregistre. Ainsi, pas d'interface monolithique, pas de couplage entre des événements indépendants, et, je l'espère, moins de code à gérer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-7488275013838376356?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/7488275013838376356/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=7488275013838376356' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7488275013838376356'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7488275013838376356'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/01/et-maintenant.html' title='Et maintenant?'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-5221174110670631158</id><published>2011-01-15T21:24:00.003+01:00</published><updated>2011-01-15T21:30:26.728+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Openrailz tech demo 3 - La vidéo</title><content type='html'>&lt;object width="560" height="420"&gt;&lt;param name="movie" value="http://www.dailymotion.com/swf/video/xgl2kp?width=560&amp;theme=none&amp;foreground=%23F7FFFD&amp;highlight=%23FFC300&amp;background=%23171D1B&amp;start=&amp;animatedTitle=&amp;iframe=0&amp;additionalInfos=0&amp;autoPlay=0&amp;hideInfos=0"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;/param&gt;&lt;embed type="application/x-shockwave-flash" src="http://www.dailymotion.com/swf/video/xgl2kp?width=560&amp;theme=none&amp;foreground=%23F7FFFD&amp;highlight=%23FFC300&amp;background=%23171D1B&amp;start=&amp;animatedTitle=&amp;iframe=0&amp;additionalInfos=0&amp;autoPlay=0&amp;hideInfos=0" width="560" height="420" allowfullscreen="true" allowscriptaccess="always"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;b&gt;&lt;a href="http://www.dailymotion.com/video/xgl2kp_openrailz-tech-demo-3_videogames"&gt;Openrailz tech demo 3&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Il a fallu franchement se battre avec les formats, mais enfin, la vidéo est là. L'on remarquera que le train à tendance à défier les lois de la physique avec ses demi-tours sur l'aile et ses démarrages et freinages au quart de tour, mais l'on a bien les fonctionnalités de base.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-5221174110670631158?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/5221174110670631158/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=5221174110670631158' title='1 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5221174110670631158'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5221174110670631158'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/01/openrailz-tech-demo-3-il-fallu.html' title='Openrailz tech demo 3 - La vidéo'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-891152278280194367</id><published>2011-01-15T18:28:00.002+01:00</published><updated>2011-01-15T18:30:18.903+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>I've got the power!</title><content type='html'>Enfin, j'ai les trains bougeant de gare en gare!&lt;br /&gt;&lt;br /&gt;Certes, c'est un petit peu bizarre par moments, les "demi-tours" dans les gares sont un poil irréalistes... Mais enfin, l'on peut contrôler le déplacement des trains à la souris, et voir le pathfinder en marche. Je vous poste une vidéo bientôt.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-891152278280194367?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/891152278280194367/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=891152278280194367' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/891152278280194367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/891152278280194367'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/01/ive-got-power.html' title='I&apos;ve got the power!'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-3963616470927681333</id><published>2011-01-15T17:36:00.002+01:00</published><updated>2011-01-15T17:40:07.477+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3d'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><category scheme='http://www.blogger.com/atom/ns#' term='client'/><title type='text'>1000ème commit</title><content type='html'>Alors j'allais quand même sortir une jolie capture d'écran pour cette occasion! Voici donc un train en gare. La plus grande partie de la logique est implémentée, il ne reste plus qu'à ajouter quelques contrôles pour pouvoir indiquer au train où aller, et l'on devrait enfin pouvoir commencer à bouger.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_c7c8R8g7is8/TTHNu9i7U2I/AAAAAAAAEZE/JcJsL0gOuG8/s1600/openrailz_train_en_gare.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 211px;" src="http://2.bp.blogspot.com/_c7c8R8g7is8/TTHNu9i7U2I/AAAAAAAAEZE/JcJsL0gOuG8/s320/openrailz_train_en_gare.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5562453221458006882" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-3963616470927681333?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/3963616470927681333/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=3963616470927681333' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3963616470927681333'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3963616470927681333'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/01/1000eme-commit.html' title='1000ème commit'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_c7c8R8g7is8/TTHNu9i7U2I/AAAAAAAAEZE/JcJsL0gOuG8/s72-c/openrailz_train_en_gare.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-8746083880379717958</id><published>2011-01-09T23:40:00.003+01:00</published><updated>2011-01-11T00:21:59.127+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='test'/><title type='text'>Tests unitaires</title><content type='html'>Mais comment ai-je pu coder pendant des années sans tests unitaires? Ce truc, c'est LA pratique qui a augmenté mon rendement, m'a permis de mieux dormir la nuit, et m'a sauvé la vie (professionnelle, tout du moins) plus d'une fois.&lt;br /&gt;&lt;br /&gt;Il y a quelques années, j'avais eu entre les mains un bouquin sur le développement orienté tests (le TTD, "Test Driven Development"), et j'avais douté leur déclaration qu'une fois touché aux tests unitaires, on ne pouvait plus s'en passer. Eh bien, ils avaient raison. Une fois utilisés correctement, les avantages sont tels qu'il devient évident que l'on ne peut vivre sans.&lt;br /&gt;&lt;br /&gt;Cependant, utilisés à mauvais escient, ils peuvent faire plus de mal que de bien. Il y a donc quelques règles à garder à l'esprit quand on se lance à écrire du code.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Les tests unitaires influencent le design. Il est rare qu'un bout de code quelconque, une fois atteint une complexité minimale, puisse être testé tel quel. Lorsque l'on sait que l'on va devoir tester le code, l'on tend à diminuer les effets de bord, à découpler ses routines, à écrire des interfaces afin de pouvoir "moquer" ses objets. Ça tombe bien, ce sont le genre d'habitudes qui améliorent la qualité du code!&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Corollaire du point précédent: il est généralement difficile d'ajouter des tests unitaires à un projet existant. Le projet dépend probablement de fichiers de configuration non moqués, force les logs vers un fichier, cause à la base de données, n'est pas séparé par bibliothèques indépendantes, dépend d'une GUI, dépend de l'horloge, écrit ses résultats dans un fichier Excel, etc. Demander tout à coup aux développeurs de "tester toute la codebase mais sans y toucher" est voué à l'échec. Pour approcher un gros projet non testé, il va falloir doucement, au fur et à mesure des nouvelles fonctionnalités ou des corrections de dysfonctionnements, tenter d'abstraire et de découpler pour pouvoir tester le changement. Au fur et à mesure que le code évolue, le nombre de tests augmente, et la qualité du produit avec.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Il existe un point où la loi des rendements décroissants entre en ligne. À moins de coder pour la NASA ou autre cas où la qualité doit être absolue, l'abus de tests unitaires rend le code plus difficile à changer (car il risque de casser une batterie de tests). Le développeur peu scrupuleux (et, croyez le ou non, il y en a!), plutôt que de plonger dans les abîmes de la perplexité, se laisse aller à sa paresse naturelle et désactive les tests urticants. Avant peu, les 3/4 des tests ont été éliminés, et ne testent plus rien du tout (point bonus aux développeurs qui désactivent les tests en commentant l'intérieur de chaque routine, afin que leur forfait n'apparaisse pas dans les statistiques de chaque build).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;À contrario, l'utilité des tests augmente exponentiellement avec leur nombre. Quelques tests sur les fonctionnalités de base ne vont probablement jamais casser, et quand bien même un bug se serait glissé dans le code, il aurait été rapidement trouvé. Tandis qu'une batterie de tests sur les fonctionnalités centrales mais plus complexes vont trouver beaucoup plus de régressions. C'est pour cela qu'il peut être difficile de convaincre certains développeurs: n'ayant rien vu venir après avoir coder leur petite dizaine de tests, ils n'en voient pas l'intérêt. Il faut persévérer!&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Le test, c'est comme le chocolat: un incomparable sentiment de plénitude lorsque la dose est bonne.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-8746083880379717958?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/8746083880379717958/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=8746083880379717958' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8746083880379717958'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8746083880379717958'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/01/tests-unitaires.html' title='Tests unitaires'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-6685029899300079311</id><published>2011-01-05T22:03:00.004+01:00</published><updated>2011-01-05T22:08:51.839+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>En voiture Simone</title><content type='html'>Je ne peux plus reculer, il n'y a plus d'échappatoire possible: la prochaine étape est vraiment de faire bouger les trains entre les gares. Pas mal de plomberie, et quelques soucis à résoudre (par exemple, je ne suis toujours pas sûr de la manière de faire faire demi-tour à mes trains...), avec je l'espère un résultat enfin visible bientôt!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-6685029899300079311?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/6685029899300079311/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=6685029899300079311' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6685029899300079311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6685029899300079311'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/01/en-voiture-simone.html' title='En voiture Simone'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-1015679304453481005</id><published>2011-01-01T17:32:00.001+01:00</published><updated>2011-01-01T17:35:45.436+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Bonne année 2011!</title><content type='html'>En plus, cette année est un nombre premier, que demander de plus.&lt;br /&gt;&lt;br /&gt;Bisous à toutes et à tous!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-1015679304453481005?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/1015679304453481005/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=1015679304453481005' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1015679304453481005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/1015679304453481005'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2011/01/bonne-annee-2011.html' title='Bonne année 2011!'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-5959858438937262674</id><published>2010-12-20T14:08:00.003+01:00</published><updated>2010-12-20T16:08:20.433+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Bug!</title><content type='html'>Les rails sont de retour, mais j'ai du rater une étape: &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_c7c8R8g7is8/TQ9VoybgrpI/AAAAAAAAEYw/ngI3Oz245ic/s1600/crossrails.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 214px;" src="http://1.bp.blogspot.com/_c7c8R8g7is8/TQ9VoybgrpI/AAAAAAAAEYw/ngI3Oz245ic/s320/crossrails.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5552751024791400082" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Voyage mouvementé en perspective?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-5959858438937262674?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/5959858438937262674/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=5959858438937262674' title='2 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5959858438937262674'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5959858438937262674'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2010/12/bug.html' title='Bug!'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_c7c8R8g7is8/TQ9VoybgrpI/AAAAAAAAEYw/ngI3Oz245ic/s72-c/crossrails.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4263139554243071140</id><published>2010-12-20T00:17:00.003+01:00</published><updated>2010-12-20T00:26:08.803+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='art'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Contrôle</title><content type='html'>Avec la réorganisation du système d'entités graphiques, construire sa voie ferrée devient plus facile (ou moins frustrant, c'est selon). Voici donc mon petit message de Noël en traverses de chemin de fer:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_c7c8R8g7is8/TQ6UHlZ-wmI/AAAAAAAAEYo/d6GWJWGnU5Q/s1600/openrailz-heart.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 196px;" src="http://1.bp.blogspot.com/_c7c8R8g7is8/TQ6UHlZ-wmI/AAAAAAAAEYo/d6GWJWGnU5Q/s320/openrailz-heart.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5552538248615477858" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4263139554243071140?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4263139554243071140/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4263139554243071140' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4263139554243071140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4263139554243071140'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2010/12/controle.html' title='Contrôle'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_c7c8R8g7is8/TQ6UHlZ-wmI/AAAAAAAAEYo/d6GWJWGnU5Q/s72-c/openrailz-heart.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-7526334404883321959</id><published>2010-12-16T22:24:00.004+01:00</published><updated>2010-12-16T22:43:40.149+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>C++0x - Moins de Boost, plus de Standard</title><content type='html'>Je me suis livré à un petit nettoyage de mes en-têtes précompilées, en enlevant les en-têtes Boost pour lesquelles j'avais un remplacement en C++0x.&lt;br /&gt;&lt;br /&gt;Peu de gain, au final, puisque j'économise environ 12Mo sur des précompilations faisant entre 120 et 300Mo, mais c'est toujours ça de pris, sans compter un code plus cohérent. Voici les remplacements:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&amp;lt;boost/shared_ptr.hpp&amp;gt; est remplacé par &amp;lt;memory&amp;gt; et son std::shared_ptr&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&amp;lt;boost/scoped_ptr.hpp&amp;gt; et &amp;lt;boost/scoped_array.hpp&amp;gt; sont remplacés par l'excellent std::unique_ptr&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&amp;lt;boost/static_assert.hpp&amp;gt; est remplacé par static_assert&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&amp;lt;boost/optional.hpp&amp;gt; vire à cause des soucis d'aliasing&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&amp;lt;boost/enable_shared_from_this.hpp&amp;gt; est fourni par std::shared_from_this&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&amp;lt;boost/thread.hpp&amp;gt; est remplacé par &amp;lt;thread&amp;gt;. Attention cependant, pas encore de groupes de threads dans le standard!&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&amp;lt;boost/non_copyable.hpp&amp;gt; est remplacé par les suppressions de méthodes (mot-clé delete)&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-7526334404883321959?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/7526334404883321959/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=7526334404883321959' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7526334404883321959'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/7526334404883321959'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2010/12/c0x-moins-de-boost-plus-de-standard.html' title='C++0x - Moins de Boost, plus de Standard'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-431373657393760779</id><published>2010-12-11T22:22:00.002+01:00</published><updated>2010-12-11T22:38:18.628+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3d'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Bibliothèque piglet</title><content type='html'>La bibliothèque piglet pour "Platform Independent Graphical Layer Entity Tools" (désolé, pas pu m'empêcher...) sépare enfin le système d'entités, lequel reçoit un lifting à la mesure de son importance. J'ai des pages couvertes de diagrammes de classes, mais l'idée est d'avoir plusieurs types d'entités, contenant chacun un objet graphique abstrait. L'implémentation OSG s'effectue en implémentant l'interface d'objet graphique, et la modification d'objets s'opère via un visiteur (après toutes ces années, j'ai enfin compris qu'un visiteur n'était qu'un double dispatch un peu bidouillé, mieux vaut tard que jamais...).&lt;br /&gt;&lt;br /&gt;Dans l'immédiat, ça ne va pas donner beaucoup de différences à l'écran (et ça commence à faire un moment, me hurlera ma horde de fans déchaînés, qui n'aura pas tort), mais cela permettra enfin, je l'espère, d'implémenter de manière à peu près correcte des objets qui s'animent en temps réel, notamment les voies lors de l'ajustement des waypoints.&lt;br /&gt;&lt;br /&gt;C'est reculer pour mieux sauter, et c'est probablement la meilleure manière d'arriver quelque part. Le système d'entités a démarré très simplement, et a fait un boulot admirable jusqu'ici. Les besoins autour de l'affichage des objets graphiques sont maintenant plus clairs, et surtout j'ai une implémentation qui marche. C'est donc maintenant, ni trop tôt et ni trop tard, qu'est le moment idéal pour retravailler le module en profondeur.&lt;br /&gt;&lt;br /&gt;Sinon, et sur un tout autre sujet, je pense enfin pouvoir me débarrasser des derniers boost::shared_ptr du code et les remplacer par des std::shared_ptr, avec l'espoir, entre autres, de virer quelques fichiers d'en têtes de ma pré-compilation pour retarder du même coup le moment où il va me falloir investir dans quelques barrettes de RAM.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-431373657393760779?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/431373657393760779/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=431373657393760779' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/431373657393760779'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/431373657393760779'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2010/12/bibliotheque-piglet.html' title='Bibliothèque piglet'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-4318186903151148741</id><published>2010-12-07T23:17:00.003+01:00</published><updated>2010-12-07T23:53:32.560+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>C++0x - Chronomètres</title><content type='html'>Enfin, et c'est pas trop tôt, une interface C++ pour mesurer le temps. Celle-ci vient de plus avec d'intéressantes fonctionnalités. Mais voyons d'abord un petit programme d'exemple:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;chrono&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  auto t1 = std::chrono::system_clock::now();&lt;br /&gt;  usleep(100000);&lt;br /&gt;  auto t2 = std::chrono::system_clock::now();&lt;br /&gt;&lt;br /&gt;  std::cout &amp;lt;&amp;lt; (t2 - t1).count() &amp;lt;&amp;lt; std::endl;&lt;br /&gt;  &lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Tout bête! Remarquez l'utilisation de &lt;i&gt;auto&lt;/i&gt; pour ne pas avoir à m'ennuyer à définir le complexe type retourné par la méthode statique. Cependant, et c'est là que je trouve que le standard fait très fort, les types fournis permettent de s'affranchir totalement des problèmes d'unités souvent rencontrés dans ces cas là: quelle est la précision fournie par la bibliothèque? Et quelle est la précision voulue par l'utilisateur? C'est là que le type &lt;i&gt;duration&lt;/i&gt; (ici implicite) de &lt;i&gt;(t2 - t1)&lt;/i&gt; donne toute sa mesure. Regardons plutôt:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;chrono&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  auto t1 = std::chrono::system_clock::now();&lt;br /&gt;  usleep(100000);&lt;br /&gt;  auto t2 = std::chrono::system_clock::now();&lt;br /&gt;  &lt;br /&gt;  std::chrono::nanoseconds n = (t2 - t1);&lt;br /&gt;  std::cout &amp;lt;&amp;lt; n.count() &amp;lt;&amp;lt; std::endl;&lt;br /&gt;&lt;br /&gt;  std::chrono::microseconds u = (t2 - t1);&lt;br /&gt;  std::cout &amp;lt;&amp;lt; u.count() &amp;lt;&amp;lt; std::endl;&lt;br /&gt;&lt;br /&gt;  std::chrono::duration&amp;lt;double&amp;gt; d = (t2 - t1);&lt;br /&gt;  std::cout &amp;lt;&amp;lt; d.count() &amp;lt;&amp;lt; std::endl;&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Là où ça devient magique, c'est que la valeur est automatiquement convertie dans l'unité demandée. Le programme affiche:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;100059000&lt;br /&gt;100059&lt;br /&gt;0.100059&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ces types &lt;i&gt;std::chrono::nanoseconds&lt;/i&gt; et &lt;i&gt;std::chrono::microseconds&lt;/i&gt; sont des typedef sur le type &lt;i&gt;duration&lt;/i&gt;, lequel prend comme paramètres templates le type de base, et un ratio (avec un défaut de 1, pour les secondes).&lt;br /&gt;&lt;br /&gt;Et, cerise sur le gâteau, g++ refusera même de compiler une conversion non exacte. La ligne &lt;pre&gt;std::chrono::seconds s = (t2 - t1);&lt;/pre&gt; renvoie le message d'erreur suivant:&lt;pre&gt;error: static assertion failed: "the resulting duration is not exactly representable"&lt;/pre&gt; En effet, le typedef &lt;i&gt;std::seconds&lt;/i&gt; prenant en type de base un entier, la conversion perd en précision. Pour que cela marche, il faut utiliser un double, comme dans l'exemple précédent.&lt;br /&gt;&lt;br /&gt;Qui a dit que le C++ n'était pas intuitif? :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-4318186903151148741?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/4318186903151148741/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=4318186903151148741' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4318186903151148741'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/4318186903151148741'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2010/12/c0x-chronometres.html' title='C++0x - Chronomètres'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-3530999517531568895</id><published>2010-12-06T23:40:00.004+01:00</published><updated>2010-12-06T23:59:48.828+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>C++0x - std::atomic</title><content type='html'>Les variables atomiques dans c++0x fournissent (enfin!) une manière standard pour protéger les types de base, avec un support automatique des instructions atomiques quand elles sont disponibles. Voyons le programme suivant avec g++4.4.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;thread&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;void increment(int &amp;amp; counter)&lt;br /&gt;{&lt;br /&gt;  for(size_t i = 0; i &amp;lt; 10000; i++)&lt;br /&gt;  {&lt;br /&gt;    counter++;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void decrement(int &amp;amp; counter)&lt;br /&gt;{&lt;br /&gt;  for(size_t i = 0; i &amp;lt; 10000; i++)&lt;br /&gt;  {&lt;br /&gt;    counter--;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  int counter;&lt;br /&gt;&lt;br /&gt;  std::thread t1(&amp;amp;increment, std::ref(counter));&lt;br /&gt;  std::thread t2(&amp;amp;decrement, std::ref(counter));&lt;br /&gt;  &lt;br /&gt;  t1.join();&lt;br /&gt;  t2.join();&lt;br /&gt;&lt;br /&gt;  std::cout &amp;lt;&amp;lt; counter &amp;lt;&amp;lt; std::endl;&lt;br /&gt;  &lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;C'est prévisible, le programme va afficher des nombres totalement farfelus en sortie, car &lt;i&gt;counter&lt;/i&gt; n'est pas protégé.&lt;br /&gt;&lt;br /&gt;Maintenant, protégeons &lt;i&gt;counter&lt;/i&gt;:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;cstdatomic&amp;gt;&lt;br /&gt;#include &amp;lt;thread&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;void increment(std::atomic&amp;lt;int&amp;gt; &amp;amp; counter)&lt;br /&gt;{&lt;br /&gt;  for(size_t i = 0; i &amp;lt; 10000; i++)&lt;br /&gt;  {&lt;br /&gt;    counter++;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void decrement(std::atomic&amp;lt;int&amp;gt; &amp;amp; counter)&lt;br /&gt;{&lt;br /&gt;  for(size_t i = 0; i &amp;lt; 10000; i++)&lt;br /&gt;  {&lt;br /&gt;    counter--;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  std::atomic&amp;lt;int&amp;gt; counter;&lt;br /&gt;&lt;br /&gt;  std::thread t1(&amp;amp;increment, std::ref(counter));&lt;br /&gt;  std::thread t2(&amp;amp;decrement, std::ref(counter));&lt;br /&gt;  &lt;br /&gt;  t1.join();&lt;br /&gt;  t2.join();&lt;br /&gt;&lt;br /&gt;  std::cout &amp;lt;&amp;lt; counter &amp;lt;&amp;lt; std::endl;&lt;br /&gt;  &lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Magie de la technologie moderne, le programme affiche systématiquement un beau 0 tout rond. Un appel de la méthode &lt;i&gt;is_lock_free()&lt;/i&gt; sur &lt;i&gt;counter&lt;/i&gt; (&lt;i&gt;atomic_is_lock_free()&lt;/i&gt; sur gcc 4.5, plus avancé au niveau des standards) vous dira si votre architecture supporte les instructions atomiques.&lt;br /&gt;&lt;br /&gt;Voilà, c'est à peu près tout! A noter cependant que l'en-tête atomic a fait son arrivée dans gcc 4.5. Avec cette version, le programme d'exemple (de mémoire), serait (et avec les lambdas, s'il vous plait!):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;atomic&amp;gt;&lt;br /&gt;#include &amp;lt;thread&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  std::atomic&amp;lt;int&amp;gt; counter;&lt;br /&gt;&lt;br /&gt;  std::thread t1([&amp;amp;counter]()&lt;br /&gt;    {for(size_t i = 0; i &amp;lt; 10000; i++) counter++;});&lt;br /&gt;  std::thread t2([&amp;amp;counter]()&lt;br /&gt;    {for(size_t i = 0; i &amp;lt; 10000; i++) counter--;});&lt;br /&gt;  &lt;br /&gt;  t1.join();&lt;br /&gt;  t2.join();&lt;br /&gt;&lt;br /&gt;  std::cout &amp;lt;&amp;lt; counter &amp;lt;&amp;lt; std::endl;&lt;br /&gt;  &lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-3530999517531568895?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/3530999517531568895/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=3530999517531568895' title='4 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3530999517531568895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3530999517531568895'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2010/12/c0x-stdatomic.html' title='C++0x - std::atomic'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-3153566729577321587</id><published>2010-12-01T00:18:00.002+01:00</published><updated>2010-12-01T00:24:02.390+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>C'est mieux</title><content type='html'>Les UserObject et les callbacks semblent donner un design un peu plus raisonnable. L'envers de la médaille, c'est que je suis revenu d'un bon en arrière, et je me retrouve à ré-implémenter la création des waypoints (va falloir que je trouve bon un nom en français).&lt;br /&gt;&lt;br /&gt;Rendez-vous dans quelques semaines pour redécouvrir Openrailz pareil qu'aujourd'hui :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-3153566729577321587?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/3153566729577321587/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=3153566729577321587' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3153566729577321587'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/3153566729577321587'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2010/12/cest-mieux.html' title='C&apos;est mieux'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-8343972637789338134</id><published>2010-11-27T22:57:00.003+01:00</published><updated>2010-11-27T23:10:16.013+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>C++0x - shared_ptr, bind, et for_each</title><content type='html'>Pour ceux qui utilisaient déjà Boost, rien de fondamentalement nouveau sous le soleil: C++0x fournit enfin en standard une implémentation de pointeur partagé, ainsi que la fonction de bind qui va bien. Le vieux code Boost peut être mis à jour simplement en remplaçant vos boost:: par des std::, hormis cependant une petite subtilité: les paramètres tels _1, _2, ne sont pas dans le namespace global comme avec boost, mais dans le namespace &lt;i&gt;std::placeholders&lt;/i&gt;. L'on pourra soit faire un &lt;i&gt;using namespace std::placeholders;&lt;/i&gt;, soit, pour éviter les conflits si l'on inclut également Boost, créer un alias afin de réduire la verbosité du code.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;#include &amp;lt;memory&amp;gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;namespace p = std::placeholders;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;class Miaou&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  Miaou(const std::string &amp;amp; v):&lt;br /&gt;    m_v(v)&lt;br /&gt;  {&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  void print()&lt;br /&gt;  {&lt;br /&gt;    std::cout &amp;lt;&amp;lt; m_v &amp;lt;&amp;lt; std::endl;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt;  std::string m_v;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  std::vector&amp;lt;std::shared_ptr&amp;lt;Miaou&amp;gt; &amp;gt; v = &lt;br /&gt;    {std::shared_ptr&amp;lt;Miaou&amp;gt;(new Miaou("a")), &lt;br /&gt;     std::shared_ptr&amp;lt;Miaou&amp;gt;(new Miaou("b")), &lt;br /&gt;     std::shared_ptr&amp;lt;Miaou&amp;gt;(new Miaou("c"))};&lt;br /&gt;  &lt;br /&gt;  std::for_each(v.begin(),&lt;br /&gt;                v.end(),&lt;br /&gt;                std::bind(&amp;amp;Miaou::print, &lt;b&gt;p::_1&lt;/b&gt;));&lt;br /&gt;  &lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Avec ces constructions additionnelles de ce côté, et les lambdas de l'autre, ce sont tous les algorithmes qui deviennent bien plus utiles. Je rêve de pouvoir enfin donner à &lt;i&gt;std::accumulate&lt;/i&gt; la place qui lui revient!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-8343972637789338134?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/8343972637789338134/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=8343972637789338134' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8343972637789338134'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8343972637789338134'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2010/11/c0x-sharedptr-bind-et-foreach.html' title='C++0x - shared_ptr, bind, et for_each'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-8279109962711475037</id><published>2010-11-24T23:42:00.002+01:00</published><updated>2010-11-25T00:19:35.123+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Ça n'aura pas duré longtemps...</title><content type='html'>mais mon design est pourri. Je vous rappelle l'idée: faire dériver chaque objet (station, section de rail, etc) à la fois d'un objet logique et d'un objet graphique. Le problème, il est que les objets sont inter-dépendants: la création d'une station force la création de sections de rails associés. Donc, quand l'objet logique station est créé, comment fait-il pour créer les objets complets (logique + graphique) pour la section? L'on n'est limité à passer de complexes factories un peu partout. C'est moche, c'est compliqué, et c'est intestable. Bref, à jeter.&lt;br /&gt;&lt;br /&gt;Je suis vraiment au carrefour de l'architecture du truc, si je le fais bien, ça ira tout seul, sinon, je risque fort de me lasser à force de me battre avec le code.&lt;br /&gt;&lt;br /&gt;C'est pas grave, j'ai des tas d'idées. Dériver de l'objet logique était bien pour la gestion des objets, de leur construction et de leur destruction. Je garde donc l'idée que l'objet logique doit pouvoir posséder l'objet graphique, mais j'essaie de découpler.&lt;br /&gt;&lt;br /&gt;Chaque objet logique possède donc un "UserObject", qui dérive d'une interface. En plus de cela, la classe World est munie d'un dispatcheur, qui permet au système graphique de détecter toutes le créations et destructions d'objets logiques. À la création d'un objet logique, le système graphique peut ainsi ajouter un "UserObject" graphique. A la destruction, l'objet graphique s'en va en même temps que l'objet logique.&lt;br /&gt;&lt;br /&gt;Le concept de user objets est très courant, comme par exemple dans wxWidgets ou dans Open Scene Graph. J'ai donc bon espoir que l'idée colle également à ma logique.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-8279109962711475037?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/8279109962711475037/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=8279109962711475037' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8279109962711475037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/8279109962711475037'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2010/11/ca-naura-pas-dure-longtemps.html' title='Ça n&apos;aura pas duré longtemps...'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-425221357944499963</id><published>2010-11-21T20:13:00.003+01:00</published><updated>2010-11-21T20:30:03.893+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Boost asio - Queues de messages - Un exemple complet</title><content type='html'>Voilà un exemple complet avec un service unique, et des queues de messages parallélisables (pour Prime) et séquentielles (pour Logger). Dans l'objet &lt;i&gt;Logger&lt;/i&gt;, plutôt que de maintenir une référence sur le service, on construit un objet &lt;i&gt;strand&lt;/i&gt;, lequel garantit que tous les appels passés par lui seront séquentiels.&lt;br /&gt;&lt;br /&gt;Notez la création et la destruction de l'objet &lt;i&gt;m_work&lt;/i&gt;. Lorsqu'il est détruit, il assure que les appels à &lt;i&gt;io_service::run&lt;/i&gt; vont retourner une fois que tous les messages auront été traités, ce qui permet de terminer l'application une fois que toutes les requêtes auront été complétées. Afin également d'éviter la destruction prématurée des objets &lt;i&gt;Logger&lt;/i&gt; et &lt;i&gt;Prime&lt;/i&gt;, les appels à &lt;i&gt;boost::bind&lt;/i&gt; prennent un &lt;i&gt;shared_from_this&lt;/i&gt; qui va garder une référence sur l'objet au sein du message.&lt;br /&gt;&lt;br /&gt;Pour compiler sous Unix: &lt;pre&gt;g++ main.cpp -o main -lboost_system-mt -lboost_thread-mt&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include &lt;iostream&gt;&lt;br /&gt;#include &lt;string&gt;&lt;br /&gt;#include &lt;algorithm&gt;&lt;br /&gt;#include &lt;boost/enable_shared_from_this.hpp&gt;&lt;br /&gt;#include &lt;boost/asio.hpp&gt;&lt;br /&gt;#include &lt;boost/bind.hpp&gt;&lt;br /&gt;#include &lt;boost/thread.hpp&gt;&lt;br /&gt;#include &lt;boost/noncopyable.hpp&gt;&lt;br /&gt;#include &lt;boost/scoped_ptr.hpp&gt;&lt;br /&gt;#include &lt;boost/assign/std/vector.hpp&gt;&lt;br /&gt;&lt;br /&gt;using namespace boost::assign;&lt;br /&gt;&lt;br /&gt;class Service : public boost::noncopyable&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  Service(int nbThreads):&lt;br /&gt;    m_work(new boost::asio::io_service::work(m_service))&lt;br /&gt;  {&lt;br /&gt;    for(int i = 0; i &lt; nbThreads; ++i)&lt;br /&gt;    {&lt;br /&gt;      m_threadGroup.create_thread&lt;br /&gt;        (boost::bind(&amp;boost::asio::io_service::run, &lt;br /&gt;                     boost::ref(m_service)));&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  ~Service()&lt;br /&gt;  {&lt;br /&gt;    m_work.reset();&lt;br /&gt;    m_threadGroup.join_all();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  boost::asio::io_service &amp; getService()&lt;br /&gt;  {&lt;br /&gt;    return m_service;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt;  boost::asio::io_service m_service;&lt;br /&gt;  boost::scoped_ptr&lt;boost::asio::io_service::work&gt; m_work;&lt;br /&gt;  boost::thread_group m_threadGroup;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class Logger : public boost::noncopyable,&lt;br /&gt;               public boost::enable_shared_from_this&lt;Logger&gt;&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  Logger(boost::asio::io_service &amp; service):&lt;br /&gt;    m_strand(service)&lt;br /&gt;  {&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  void log(const std::string &amp; message)&lt;br /&gt;  {&lt;br /&gt;    m_strand.dispatch(boost::bind(&amp;Logger::doLog, &lt;br /&gt;                                  shared_from_this(), &lt;br /&gt;                                  message));&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;private:&lt;br /&gt;  void doLog(const std::string &amp; message)&lt;br /&gt;  {&lt;br /&gt;    std::cout &lt;&lt; message &lt;&lt; std::endl;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  boost::asio::io_service::strand m_strand;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class Prime : public boost::noncopyable,&lt;br /&gt;              public boost::enable_shared_from_this&lt;Prime&gt;&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  Prime(boost::asio::io_service &amp; service,&lt;br /&gt;        const boost::shared_ptr&lt;Logger&gt; &amp; logger):&lt;br /&gt;    m_service(service),&lt;br /&gt;    m_logger(logger)&lt;br /&gt;  {&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  void nthPrime(size_t n)&lt;br /&gt;  {&lt;br /&gt;    m_service.dispatch(boost::bind(&amp;Prime::doNthPrime, &lt;br /&gt;                                   shared_from_this(), &lt;br /&gt;                                   n));&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;private:&lt;br /&gt;  void doNthPrime(size_t n)&lt;br /&gt;  {&lt;br /&gt;    std::vector&lt;size_t&gt; primes(1, 2);&lt;br /&gt;    size_t current = 2;&lt;br /&gt;    while(primes.size() &lt; n)&lt;br /&gt;    {&lt;br /&gt;      current++;&lt;br /&gt;      size_t i;&lt;br /&gt;      for(i = 0; i &lt; primes.size(); ++i)&lt;br /&gt;      {&lt;br /&gt;        if(current % primes.at(i) == 0)&lt;br /&gt;          break;&lt;br /&gt;      }&lt;br /&gt;      if(i &gt;= primes.size())&lt;br /&gt;      {&lt;br /&gt;        primes.push_back(current);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    std::ostringstream str;&lt;br /&gt;    str &lt;&lt; n &lt;&lt; "th prime is " &lt;&lt; primes.at(n - 1);&lt;br /&gt;    m_logger-&gt;log(str.str());&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  boost::asio::io_service &amp; m_service;&lt;br /&gt;  boost::shared_ptr&lt;Logger&gt; m_logger;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  boost::shared_ptr&lt;Service&gt; service&lt;br /&gt;    (new Service(3));&lt;br /&gt;  boost::shared_ptr&lt;Logger&gt; logger&lt;br /&gt;    (new Logger(service-&gt;getService()));&lt;br /&gt;  boost::shared_ptr&lt;Prime&gt; prime&lt;br /&gt;    (new Prime(service-&gt;getService(), logger));&lt;br /&gt;  &lt;br /&gt;  std::vector&lt;size_t&gt; values;&lt;br /&gt;  values += &lt;br /&gt;    20000, 10000, 5000, 7500, 15000,&lt;br /&gt;    17000, 14000, 11000, 21000, 11000;&lt;br /&gt;  &lt;br /&gt;  std::for_each(values.begin(),&lt;br /&gt;                values.end(),&lt;br /&gt;                boost::bind(&amp;Prime::nthPrime, prime, _1));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Asio fournit bien plus qu'une couche d'abstraction au dessus des sockets réseau. Il serait dommage de cantonner cette bibliothèque à la communication client serveur, alors qu'elle fournit un paradigme puissant pour construire des applications événementielles sans avoir à s'arracher les cheveux sur les problèmes bas-niveau.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-425221357944499963?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/425221357944499963/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=425221357944499963' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/425221357944499963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/425221357944499963'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2010/11/boost-asio-queues-de-messages-un.html' title='Boost asio - Queues de messages - Un exemple complet'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-6434563883985661274</id><published>2010-11-21T15:12:00.005+01:00</published><updated>2010-11-21T20:23:20.255+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><title type='text'>Boost asio - Queues de messages</title><content type='html'>La bibliothèque Asio, intégrée à Boost, permet de gérer des événements de manière asynchrone. Principalement utilisée pour le réseau, elle peut également être très utile pour résoudre des problèmes de programmation concurrente. Un exemple très simple: la gestion de queues de messages.&lt;br /&gt;&lt;br /&gt;Prenons donc une classe qui affiche des messages sur la console. Une manière de gérer l'accès concurrent est de mettre un bon vieux mutex autour de l'appel à std::cout, forçant chaque thread à attendre sur des opérations d'entrées sorties potentiellement longues. Une autre manière, souvent plus efficace, est d'ajouter le message sur une queue, laquelle est lue par un thread unique chargé de l'affichage. Comment faire de même avec Asio?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Logger&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  Logger():&lt;br /&gt;    m_work(m_service),&lt;br /&gt;    m_thread(boost::bind(&amp;boost::asio::io_service::run, &lt;br /&gt;                         boost::ref(m_service)))&lt;br /&gt;  {&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  ~Logger()&lt;br /&gt;  {&lt;br /&gt;    m_service.stop();&lt;br /&gt;    m_thread.join();&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  void log(const std::string &amp; message)&lt;br /&gt;  {&lt;br /&gt;    m_service.dispatch(boost::bind(&amp;Logger::doLog, this, message));&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;private:&lt;br /&gt;  void doLog(const std::string &amp; message)&lt;br /&gt;  {&lt;br /&gt;    std::cout &lt;&lt; message &lt;&lt; std::endl;&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  boost::asio::io_service m_service;&lt;br /&gt;  boost::asio::io_service::work m_work;&lt;br /&gt;  boost::thread m_thread;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Cette classe s'utilise simplement en instanciant l'objet &lt;i&gt;Logger&lt;/i&gt;, puis en appelant la méthode &lt;i&gt;log&lt;/i&gt;. L'appel à &lt;i&gt;log&lt;/i&gt; est thread safe, et peut donc être appelé par n'importe quel thread de l'application. L'affichage, lui, ne tourne que depuis le thread interne de la classe. Pas de mutex, pas de conditions, tout est planqué dans Asio.&lt;br /&gt;&lt;br /&gt;Remarquez l'objet &lt;i&gt;work&lt;/i&gt;, qui indique à &lt;i&gt;m_service&lt;/i&gt; qu'il y a toujours quelque chose à faire, pour éviter que &lt;i&gt;m_service.run()&lt;/i&gt; ne retourne prématurément. &lt;br /&gt;&lt;br /&gt;Et pour l'opération inverse, c'est à dire l'utilisation d'une queue de messages pour faire tourner des calculs potentiellement lourds simultanément? C'est à peine plus complexe, comme par exemple dans cette classe qui calcule le n-ième nombre premier.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class Prime&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;  Prime():&lt;br /&gt;    m_work(m_service)&lt;br /&gt;  {&lt;br /&gt;    m_threadGroup.create_thread(boost::bind(&amp;boost::asio::io_service::run, &lt;br /&gt;                                            boost::ref(m_service)));&lt;br /&gt;    m_threadGroup.create_thread(boost::bind(&amp;boost::asio::io_service::run, &lt;br /&gt;                                            boost::ref(m_service)));&lt;br /&gt;    m_threadGroup.create_thread(boost::bind(&amp;boost::asio::io_service::run, &lt;br /&gt;                                            boost::ref(m_service)));&lt;br /&gt;    m_threadGroup.create_thread(boost::bind(&amp;boost::asio::io_service::run, &lt;br /&gt;                                            boost::ref(m_service)));&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  ~Prime()&lt;br /&gt;  {&lt;br /&gt;    m_service.stop();&lt;br /&gt;    m_threadGroup.join_all();&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  void nthPrime(size_t n)&lt;br /&gt;  {&lt;br /&gt;    m_service.dispatch(boost::bind(&amp;Prime::doNthPrime, this, n));&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;private:&lt;br /&gt;  void doNthPrime(size_t n)&lt;br /&gt;  {&lt;br /&gt;    std::vector&lt;size_t&gt; primes(1, 2);&lt;br /&gt;    size_t current = 2;&lt;br /&gt;    while(primes.size() &lt; n)&lt;br /&gt;    {&lt;br /&gt;      current++;&lt;br /&gt;      size_t i;&lt;br /&gt;      for(i = 0; i &lt; primes.size(); ++i)&lt;br /&gt;      {&lt;br /&gt;        if(current % primes.at(i) == 0)&lt;br /&gt;          break;&lt;br /&gt;      }&lt;br /&gt;      if(i &gt;= primes.size())&lt;br /&gt;      {&lt;br /&gt;        primes.push_back(current);&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    std::cout &lt;&lt; primes.at(n - 1);&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  boost::asio::io_service m_service;&lt;br /&gt;  boost::asio::io_service::work m_work;&lt;br /&gt;  boost::thread_group m_threadGroup;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Faisant tourner 4 threads à partir du bon vieux thread pool de chez Boost, cette classe va empiler les requêtes et n'en faire tourner que 4 maximum à la fois.&lt;br /&gt;&lt;br /&gt;L'étape suivant serait d'appeler Logger depuis Prime, afin de n'afficher le résultat que depuis un seul thread. L'on peut ainsi construire un programme à partir de briques de base qui gèrent elles-mêmes l'accès concurrent, sans avoir à se (trop) se préoccuper de l'accès concurrent ou d'interbloquages.&lt;br /&gt;&lt;br /&gt;Cette approche est cependant limitée par l'explosion du nombre de threads dans l'application, chaque brique gérant un certain nombre de threads indépendants. Lorsque la charge de travail est lourde, l'on risque de se retrouver avec beaucoup plus de threads tentant de s'exécuter que de processeurs.&lt;br /&gt;&lt;br /&gt;L'on peut alors modifier quelque peu son approche, pour partager un même service asio au sein du programme, et laisser à la bibliothèque le soin d'ordonnancer les tâches.&lt;br /&gt;&lt;br /&gt;S'assurer que l'accès à certaines ressources demeure séquentiel, comme pour notre Logger, peut se faire grâce aux &lt;i&gt;strands&lt;/i&gt;. Démonstration dans un prochain post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-6434563883985661274?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/6434563883985661274/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=6434563883985661274' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6434563883985661274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/6434563883985661274'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2010/11/boost-asio-queues-de-messages.html' title='Boost asio - Queues de messages'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-5009647353761643024</id><published>2010-11-19T00:35:00.002+01:00</published><updated>2010-11-19T00:40:06.490+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='programmation'/><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Pas assez d'objet?</title><content type='html'>Je ne suis pas satisfait de mon design autour des concepts principaux d'OpenRailz que sont les sections de rails et les stations. Peut-être ais-je péché par excès d'anti-POO primaire, et, cherchant un style plus fonctionnel, me retrouve avec quantités de collections d'objets. Je cherche donc à centraliser un petit peu, pour une fois, en utilisant le bon vieil héritage multiple (que je pourrais transformer en interface à un moment ou à un autre, c'est à voir). &lt;br /&gt;&lt;br /&gt;Le résultat, c'est que plutôt que de séparer ma station de l'entité la représentant, je créé une classe StationEntity qui dérive à la fois de Station et de OsgEntity. &lt;br /&gt;&lt;br /&gt;Nous verrons ce que cela donne.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-5009647353761643024?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/5009647353761643024/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=5009647353761643024' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5009647353761643024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5009647353761643024'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2010/11/pas-assez-dobjet.html' title='Pas assez d&apos;objet?'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-949706588497831852.post-5821669688543263454</id><published>2010-11-14T17:02:00.004+01:00</published><updated>2010-11-14T17:08:08.197+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='humeur'/><title type='text'>Fallout 3 - New Vegas - C'est plié</title><content type='html'>Après 50 heures de jeu, me voilà déjà à la fin... Ou plutôt, une des fins. Fallout 3 New Vegas a tenu toutes les promesses, les quêtes étaient intéressantes, interactives et profondes, les personnages attachants, et l'histoire tout à fait prenante.&lt;br /&gt;&lt;br /&gt;J'hésite maintenant entre reprendre une sauvegarde un peu en arrière et essayer d'autres fins, ou tout redémarrer du début avec une ligne très différente. Mais là, tout de suite, je vais plutôt me remettre à coder. Faut que je me remette de mon overdose!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/949706588497831852-5821669688543263454?l=aubedesheros.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://aubedesheros.blogspot.com/feeds/5821669688543263454/comments/default' title='Publier les commentaires'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=949706588497831852&amp;postID=5821669688543263454' title='0 commentaires'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5821669688543263454'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/949706588497831852/posts/default/5821669688543263454'/><link rel='alternate' type='text/html' href='http://aubedesheros.blogspot.com/2010/11/fallout-3-new-vegas-cest-plie.html' title='Fallout 3 - New Vegas - C&apos;est plié'/><author><name>M87</name><uri>http://www.blogger.com/profile/01230411662211999500</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://bp3.blogger.com/_c7c8R8g7is8/SHf5p3drzsI/AAAAAAAABao/ISwISn9B9Zs/S220/depth.jpg'/></author><thr:total>0</thr:total></entry></feed>
