<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-8589498860624285456</atom:id><lastBuildDate>Thu, 24 Oct 2024 07:04:30 +0000</lastBuildDate><category>c++</category><category>c#</category><category>v8</category><category>java</category><category>blog</category><category>c++ tcl</category><category>html</category><title>Delirium Corp</title><description>Du code, de l&#39;ironie, de la vulgarité et un peu d&#39;intelligence de la part d&#39;un certain Etienne de Martel</description><link>http://deliriumcorp.blogspot.com/</link><managingEditor>noreply@blogger.com (Etienne de Martel)</managingEditor><generator>Blogger</generator><openSearch:totalResults>14</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8589498860624285456.post-5962099519243606660</guid><pubDate>Sun, 10 Apr 2011 22:04:00 +0000</pubDate><atom:updated>2011-04-10T18:28:51.809-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">c#</category><title>C#: Convertir des types valeurs avec as</title><description>Je me devais de faire part de la découverte suivante.&lt;br /&gt;&lt;br /&gt;En C#, l&#39;opérateur as permet de combiner deux opérations communes: tester si un objet est convertible en un type, et effectuer la conversion à proprement parler. Si la conversion échoue, ou si la référence est déjà nulle, as retourne null. Ainsi:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;csharp&quot;&gt;&lt;br /&gt;var val = ...;&lt;br /&gt;&lt;br /&gt;// les deux bouts suivants sont équivalents:&lt;br /&gt;var covt1 = val as Type;&lt;br /&gt;var covt2 = val is Type ? (Type)val : null;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Un bon exemple serait une redéfinition de la méthode Equals:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;csharp&quot;&gt;&lt;br /&gt;class T&lt;br /&gt;{&lt;br /&gt;    // ...&lt;br /&gt;&lt;br /&gt;    public override bool Equals(object obj)&lt;br /&gt;    {&lt;br /&gt;        var other = obj as T;&lt;br /&gt;        if(other == null)&lt;br /&gt;            return false; // couvre obj == null et !(obj is T)&lt;br /&gt;&lt;br /&gt;        // utiliser other pour la comparaison&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;En ce sens, c&#39;est un équivalent direct du dynamic_cast de C++, lorsque celui-ci est utilisé sur des pointeurs.&lt;br /&gt;&lt;br /&gt;Il y a néanmoins un défaut avec ce opérateur: as retourne null quand la conversion échoue, et null n&#39;est pas une valeur valide pour les types valeur (les struct). On ne peut donc pas utiliser as pour caster un struct.&lt;br /&gt;&lt;br /&gt;En pratique, ce n&#39;est pas trop problématique: les structs héritent tous de System.ValueType, sont implicitement sealed, et ne peuvent donc pas faire partie d&#39;une hiérarchie de classe. Les downcastings de ce genre sont rares.&lt;br /&gt;&lt;br /&gt;Mais il ne faut pas oublier un détail: un struct hérite également de System.Object, et il possible de faire un downcasting de object à un struct (une procédure appelée &quot;unboxing&quot;). Pour ces cas, donc, j&#39;en étais réduit à l&#39;approche verbeuse (is + cast).&lt;br /&gt;&lt;br /&gt;Or, j&#39;ai récemment découvert quelque chose d&#39;intéressant: il est possible d&#39;utiliser as avec un type valeur si celui-ci est nullable:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;csharp&quot;&gt;&lt;br /&gt;struct V&lt;br /&gt;{&lt;br /&gt;    // ...&lt;br /&gt;&lt;br /&gt;    public override bool Equals(object obj)&lt;br /&gt;    {&lt;br /&gt;        var other = obj as V?; // le ? est un raccourci pour Nullable&amp;lt;V&amp;gt;&lt;br /&gt;        if(!other.HasValue)&lt;br /&gt;            return false;&lt;br /&gt;    &lt;br /&gt;         // utiliser other.Value pour la comparaison&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;MSDN n&#39;en parle pas, mais c&#39;est très intéressant. Testé avec C# 4.0, donc ce n&#39;est peut-être pas disponible pour les versions précédentes. Nullable ayant été introduit en .NET 2.0, il est certain que ça ne fonctionnera pas avant.</description><link>http://deliriumcorp.blogspot.com/2011/04/c-convertir-des-types-valeurs-avec-as.html</link><author>noreply@blogger.com (Etienne de Martel)</author><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8589498860624285456.post-8156639605168723255</guid><pubDate>Fri, 01 Jan 2010 20:45:00 +0000</pubDate><atom:updated>2010-01-01T19:01:02.401-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">c++</category><category domain="http://www.blogger.com/atom/ns#">java</category><title>Extraire les classes et méthodes Java d&#39;un fichier .class en C++?</title><description>Avant de commencer, bonne année 2010 à tous!&lt;br /&gt;&lt;br /&gt;La plupart des IDEs pour Java sur le marché (dont les deux plus populaires, Eclipse et NetBeans) sont eux-mêmes écrits en Java. Cela n&#39;est pas vraiment un problème en soit: j&#39;utilise Eclipse pour le développement Java, et NetBeans est &lt;i&gt;de facto&lt;/i&gt; l&#39;IDE officiel pour le langage. De plus, écrire dans un langage avec un outil écrit dans le même langage est plutôt commun: Visual Studio est écrit en C++, et ça reste quand même un des meilleurs IDEs C++ existant.&lt;br /&gt;&lt;br /&gt;Cherchant toujours n&#39;importe quel prétexte pour me mettre à coder, je me suis dis qu&#39;il serait intéressant de coder un IDE pour Java, avec la particularité qu&#39;il serait écrit en C++. L&#39;objectif étant d&#39;en faire un assez rapide et prenant relativement peu de mémoire (n&#39;importe qui utilisant Eclipse et NetBeans sait à quel point il sont lents au démarrage et qu&#39;ils bouffent les ressources de façon assez impressionnante). Surtout que je n&#39;ai jamais vraiment fait d&#39;interface graphique en C++.&lt;br /&gt;&lt;br /&gt;Les fonctionnalités prévues seraient plutôt standard: coloration syntaxique, auto-complétion, refactoring, etc. Je préfère ne pas être trop ambitieux et ne pas parler tout de suite de débogueur.&lt;br /&gt;&lt;br /&gt;Je sais, je sais, rien de tout cela n&#39;est facile. Mais en fait, tout ceci n&#39;est qu&#39;un gros prétexte pour ce qui me fascine le plus: l&#39;auto-complétion. Cela impliquerait de construire en mémoire une représentation des classes (avec leurs méthodes et attributs) présentes dans le classpath. Lorsque l&#39;utilisateur entrera du code et aura besoin d&#39;aide de la part de l&#39;IDE, on pourrait ensuite faire une recherche selon divers critères dans cette représentation et présenter les résultats au programmeur, qui n&#39;aurait qu&#39;à choisir l&#39;élément le plus approprié.&lt;br /&gt;&lt;br /&gt;Le plus difficile reste donc de construire la représentation en question. Et c&#39;est là que ça se corse. Un compilateur Java insère des métadonnées dans le bytecode généré pour permettre certaines choses comme la réflexion. Il serait donc techniquement possible d&#39;extraire les métadonnées du code pour construire la représentation. Sauf que ce n&#39;est pas simple à faire. Je pourrais bien sûr exécuter &lt;a href=&quot;http://java.sun.com/j2se/1.5.0/docs/tooldocs/windows/javap.html&quot;&gt;javap&lt;/a&gt; avec les bons paramètres et ensuite analyser la sortie, mais ça me semble un peu paresseux.&lt;br /&gt;&lt;br /&gt;En tout cas, je vais faire des recherches sur le sujet, et je vous reviens avec ce que j&#39;ai trouvé.</description><link>http://deliriumcorp.blogspot.com/2010/01/extraire-les-classes-et-methodes-java.html</link><author>noreply@blogger.com (Etienne de Martel)</author><thr:total>4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8589498860624285456.post-9177007218813795333</guid><pubDate>Sat, 10 Oct 2009 16:46:00 +0000</pubDate><atom:updated>2009-10-10T19:38:32.585-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">java</category><title>Java: Un tableau itérable</title><description>Dans le .NET Framework, on retrouve l&#39;interface IEnumerable (ainsi que sa version générique, IEnumerable&amp;lt;T&amp;gt; depuis la version 2.0). Toute classe implémentant cette interface pourra être parcourue avec un foreach.&lt;br /&gt;&lt;br /&gt;Java possède, depuis sa version 1.5, un équivalent, l&#39;interface Iterable. Une classe implémentant Iterable pourra être parcourue avec un for.&lt;br /&gt;&lt;br /&gt;En C#, j&#39;ai tendance à utiliser le plus possible IEnumerable: c&#39;est le dénominateur commun. Alors quand je me suis mis à faire du Java, j&#39;ai décidé d&#39;employer Iterable pour les mêmes raisons. Sauf que j&#39;ai découvert quelque chose d&#39;étrange.&lt;br /&gt;&lt;br /&gt;Avec .NET, les tableaux implémentent IEnumerable. On peut donc passer un tableau à une méthode qui attend un IEnumerable en paramètre. Or, en Java, les tableaux n&#39;implémentent pas Iterable. On peut les parcourir comme un Iterable, mais c&#39;est probablement du à une &quot;patch&quot; du compilateur. Je n&#39;ai aucune idée de pourquoi est-ce que c&#39;est le cas, mais toujours est-il qu&#39;on ne peut donc pas faire la même chose qu&#39;avec .NET.&lt;br /&gt;&lt;br /&gt;Mais ce n&#39;est pas vraiment un problème. Il suffit de coder un adaptateur! Et c&#39;est ce que j&#39;ai fait:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;java&quot;&gt;&lt;br /&gt;import java.util.Iterator;&lt;br /&gt;import java.util.NoSuchElementException;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; * Un adaptateur permettant d&#39;utiliser un tableau là où un Iterable&amp;lt;T&amp;gt; est requis&lt;br /&gt; * @author Etienne de Martel&lt;br /&gt; * @param &amp;lt;T&amp;gt; Le type d&#39;un élément du tableau&lt;br /&gt; */&lt;br /&gt;public class IterableArray&amp;lt;T&amp;gt; implements Iterable&amp;lt;T&amp;gt;&lt;br /&gt;{&lt;br /&gt;    // Un itérateur sur un tableau&lt;br /&gt;    private class ArrayIterator implements Iterator&amp;lt;T&amp;gt;&lt;br /&gt;    {&lt;br /&gt;        T[] _array;&lt;br /&gt;        int _index;&lt;br /&gt;  &lt;br /&gt;        public ArrayIterator(T[] array)&lt;br /&gt;        {&lt;br /&gt;            _array = array;&lt;br /&gt;            _index = 0;&lt;br /&gt;        }&lt;br /&gt;  &lt;br /&gt;        @Override&lt;br /&gt;        public boolean hasNext() &lt;br /&gt;        {&lt;br /&gt;            return _index &amp;lt; _array.length;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        @Override&lt;br /&gt;        public T next() &lt;br /&gt;        {&lt;br /&gt;            if(!hasNext())&lt;br /&gt;                throw new NoSuchElementException();&lt;br /&gt;            return _array[_index++];&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        // Cet itérateur est en lecture seule&lt;br /&gt;        @Override&lt;br /&gt;        public void remove() &lt;br /&gt;        {&lt;br /&gt;            throw new UnsupportedOperationException();&lt;br /&gt;        }&lt;br /&gt;  &lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;    private T[] _array;&lt;br /&gt; &lt;br /&gt;    /**&lt;br /&gt;     * Construit un nouvel adaptateur&lt;br /&gt;     * @param array Le tableau autour duquel l&#39;adaptateur sera construit&lt;br /&gt;     * @throws NullPointerException Le tableau passé en paramêtre est null&lt;br /&gt;     */&lt;br /&gt;    public IterableArray(T[] array) throws NullPointerException&lt;br /&gt;    {&lt;br /&gt;        if(array == null)&lt;br /&gt;            throw new NullPointerException(&amp;quot;array cannot be null&amp;quot;);&lt;br /&gt;        _array = array;&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;    @Override&lt;br /&gt;    public Iterator&amp;lt;T&amp;gt; iterator() &lt;br /&gt;    {&lt;br /&gt;        return new ArrayIterator(_array);&lt;br /&gt;    }&lt;br /&gt; &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Voilà. Have fun.</description><link>http://deliriumcorp.blogspot.com/2009/10/java-un-tableau-iterable.html</link><author>noreply@blogger.com (Etienne de Martel)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8589498860624285456.post-8488376410421094236</guid><pubDate>Mon, 28 Sep 2009 04:55:00 +0000</pubDate><atom:updated>2009-10-04T13:00:00.003-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">c#</category><category domain="http://www.blogger.com/atom/ns#">c++</category><title>Différences entre les templates de C++ et les Generics de C#</title><description>Ne vous inquiétez pas, je devrais arriver avec des choses plus intéressantes dans les jours à venir (si j&#39;ai le temps)...&lt;br /&gt;&lt;br /&gt;Les templates de C++ permettent d&#39;écrire du code générique, c&#39;est à dire de se faire chier une seule fois pour ensuite pouvoir utiliser le même code partout. Enfin, c&#39;était là leur but premier, et puis un gars (David Vandevoorde, si je me souviens bien) a découvert qu&#39;elles étaient &lt;a href=&quot;http://en.wikipedia.org/wiki/Turing_completeness&quot; target=&quot;_blank&quot;&gt;turing complete&lt;/a&gt;. Cela signifie qu&#39;on peut écrire, avec des templates, des programmes qui s&#39;exécuteront à la compilation.&lt;br /&gt;&lt;br /&gt;L&#39;exemple le plus répandu est une factorielle en O(1):&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;template&amp;lt;int N&amp;gt;&lt;br /&gt;struct Factorial&lt;br /&gt;{&lt;br /&gt;    static const int Value = N * Factorial&amp;lt;N - 1&amp;gt;::Value;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;template&amp;lt;&amp;gt;&lt;br /&gt;struct Factorial&amp;lt;0&amp;gt;&lt;br /&gt;{&lt;br /&gt;    static const int Value = 1;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;    std::cout &amp;lt;&amp;lt; Factorial&amp;lt;6&amp;gt;::Value; // affiche 720&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;La valeur de la factorielle sera évaluée à la compilation, et sera équivalente à une constante.&lt;br /&gt;&lt;br /&gt;On peut également créer des assertions statiques (des tests qui font planter la compilation s&#39;ils ne passent pas) avec des templates. À noter qu&#39;une telle pratique sera rendue obsolète en C++0x, qui inclura un support standard pour de telles assertions.&lt;br /&gt;&lt;br /&gt;En Java, pour éviter les abus de downcasts de Object à quelque chose, on a introduit dans la version 1.5 les Generics. C# a eu tôt fait de copier le concept dans sa version 2.0. Mis à part une syntaxe légèrement différente pour les contraintes, la principale nuance entre C# et Java est qu&#39;en Java, les Generics sont remplacés par des Object avec des casts, alors qu&#39;en C#, ils sont remplacés par le type utilisé. Ces deux approches se valent, bien que je préfère celle de C#: elle permet, entre autres, d&#39;effectuer de la réflexion sur les types génériques.&lt;br /&gt;&lt;br /&gt;Pour celui qui connaît peu les templates de C++, on serait porté à croire que les Generics sont très semblables, mais il y a énormément de différences entre les deux. La plus importante est que les templates sont instanciés à la compilation, et le compilateur peut donc évaluer immédiatement si elles sont correctement utilisées (et si ce n&#39;est pas le cas, générer un message d&#39;erreur incompréhensible). En Java et en C#, les generics sont instanciés à l&#39;exécution, et le compilateur ne peut donc pas s&#39;assurer qu&#39;elles sont bien utilisées. Le programmeur doit donc insérer des &quot;contraintes&quot;, sinon, le type générique sera considéré comme un Object, ce qui tue un peu le principe. De telles contraintes sont inutiles en C++, car les templates répondent au principe de &lt;a href=&quot;http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error&quot; target=&quot;_blank&quot;&gt;SFINAE&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Pourquoi une telle discussion? J&#39;ai trouvé un vieil article sur MSDN décrivant les différences entre les templates de C++ et les Generics de C#:&lt;br /&gt;&lt;a href=&quot;http://msdn.microsoft.com/en-us/library/c6cyy67b%28loband%29.aspx&quot; target=&quot;_blank&quot;&gt;http://msdn.microsoft.com/en-us/library/c6cyy67b(loband).aspx&lt;/a&gt;&lt;br /&gt;En passant, pour ceux qui ne le savent pas, le &quot;(loband)&quot; dans l&#39;URL, c&#39;est pour activer le &quot;low bandwidth mode&quot; sur MSDN, vous permettant de sauver de la bande passante.&lt;br /&gt;&lt;br /&gt;Voilà.</description><link>http://deliriumcorp.blogspot.com/2009/09/differences-entre-les-templates-de-c-et.html</link><author>noreply@blogger.com (Etienne de Martel)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8589498860624285456.post-7223288451230129735</guid><pubDate>Sun, 09 Aug 2009 21:49:00 +0000</pubDate><atom:updated>2009-08-09T18:32:26.957-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">c++</category><title>Truc C++ #1: Initialiser une string avec le contenu d&#39;un flux</title><description>(Désolé pour le titre interminable)&lt;br /&gt;&lt;br /&gt;C&#39;est pas compliqué, mais fallait y penser.&lt;br /&gt;&lt;br /&gt;Disons que vous avez en tant qu&#39;attribut une std::string, et que vous voulez l&#39;initialiser avec le contenu d&#39;un flux reçu en paramètre au constructeur. Vous pourriez bien sûr choisir l&#39;approche lente:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;class Script&lt;br /&gt;{&lt;br /&gt;    std::string _script;&lt;br /&gt;public:&lt;br /&gt;    Script(std::istream &amp;stream)&lt;br /&gt;    {&lt;br /&gt;        std::string line;&lt;br /&gt;        while(std::getline(stream, line))&lt;br /&gt;             _script += line + &#39;\n&#39;;&lt;br /&gt;    }&lt;br /&gt;    // ...&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;Le problème avec cette technique, c&#39;est que l&#39;attribut est d&#39;abord construit avec le constructeur par défaut, puis modifié. Ce problème est dû au fait que par défaut, les objets en C++ ont une sémantique de valeur (ils sont donc traités comme des types primitifs). Si l&#39;exemple ci-dessus avait été en C# ou en Java, _script aurait été une référence null, et donc, aucune mémoire n&#39;aurait été allouée inutilement.&lt;br /&gt;&lt;br /&gt;Pour court-circuiter (+10 points pour le beau terme) la construction par défaut, il faut passer par une liste d&#39;initialisation. L&#39;un des constructeurs de std::string prend une paire d&#39;itérateurs représentant une séquence de char (wchar_t pour std::wstring). &lt;a href=&quot;http://deliriumcorp.blogspot.com/2009/07/c-implementer-un-getlineiterator.html&quot;&gt;Avec notre connaissance des std::istream_iterator&lt;/a&gt;, on serait donc tenté de faire ça:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;Script(std::istream &amp;stream)&lt;br /&gt;: _script(std::istream_iterator&amp;lt;char&amp;gt;(stream), std::istream_iterator&amp;lt;char&amp;gt;())&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Ça compile et ça ne plante même pas! Sauf que ça n&#39;a pas le résultat escompté.&lt;br /&gt;&lt;br /&gt;std::istream_iterator utilise l&#39;opérateur &amp;gt;&amp;gt;, lequel a un bien étrange comportement: il consomme tous les caractères blancs (c&#39;est-à-dire ceux pour lesquels std::isspace() retourne true pour la locale actuellement utilisée par le flux). Avec la culture classique (celle du langage C), cela signifie les espaces, les tabulations (\t), les retours chariots (\r) et les retours de ligne (\n). Notre attribut _script ne contiendra donc pas tous les éléments!&lt;br /&gt;&lt;br /&gt;La solution consiste donc à utiliser std::istreambuf_iterator, lequel n&#39;effectue aucun traitement sur le contenu du flux:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;Script(std::istream &amp;stream)&lt;br /&gt;: _script(std::istreambuf_iterator&amp;lt;char&amp;gt;(stream), std::istreambuf_iterator&amp;lt;char&amp;gt;())&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Naturellement, si vous ne voulez lire qu&#39;une partie du flux, cette technique ne fonctionnera pas.&lt;br /&gt;&lt;br /&gt;Voilà! Comme d&#39;habitude, j&#39;attends vos commentaires.</description><link>http://deliriumcorp.blogspot.com/2009/08/truc-c-1-initialiser-une-string-avec-le.html</link><author>noreply@blogger.com (Etienne de Martel)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8589498860624285456.post-6968208073790577205</guid><pubDate>Wed, 05 Aug 2009 21:58:00 +0000</pubDate><atom:updated>2009-08-06T15:03:05.952-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">c++ tcl</category><title>C++/Tcl: Premiers pas</title><description>Tcl signifie &quot;Tool Command  Language&quot;. C&#39;est un langage qui a été conçu spécifiquement pour ajouter des fonctionnalités de scripting à d&#39;autres langages. Puisqu&#39;un binding existe en standard pour le C, il s&#39;en fallu de peu pour que quelqu&#39;un ait la bonne idée d&#39;en faire un wrapper C++.&lt;br /&gt;&lt;br /&gt;Ça a pris un peu de gossage, mais je suis arrivé à faire marcher le tout sous Windows avec VC++9 (AKA Visual Studio 2008).&lt;br /&gt;&lt;br /&gt;Donc, C++/Tcl est composé de deux fichiers (un .h et un .cpp). Il a également deux dépendances: le core de Tcl et... Boost. Seuls quelques headers de Boost sont utilisés, pas besoin de linker quoique ce soit. Pour Tcl, c&#39;est une autre histoire.&lt;br /&gt;&lt;br /&gt;Ah, Boost. Quelle superbe bibliothèque. Je dois dire que je n&#39;étais jamais arrivé à la faire fonctionner. Quelle n&#39;a pas été ma surprise de découvrir qu&#39;une entreprise du nom de BoostPro Computing offrait un installateur permettant d&#39;installer Boost en mode &quot;next next finish&quot;. Ne vous inquiétez pas, c&#39;est entièrement gratuit et ça ne corromps pas la licence outre mesure. Vous pouvez obtenir ledit installateur là: &lt;a href=&quot;http://www.boostpro.com/download&quot;&gt;http://www.boostpro.com/download&lt;/a&gt;. J&#39;ai téléchargé la version 1.39, c&#39;est-à-dire la plus récente au moment d&#39;écrire ces lignes. L&#39;installateur installe par défaut toutes les bibliothèques &quot;header only&quot;. On peut également installer d&#39;autres bibliothèques (celle qui doivent être linkées à la compilation). Assurez vous de n&#39;installer que les versions allant avec le compilateur de votre choix (VC++7.1 pour VS2003, VC++8 pour VS2005 ou VC++9 pour VS2008), sinon vous allez télécharger trois fois trop de données que vous n&#39;utiliserez même pas en fin de compte!&lt;br /&gt;&lt;br /&gt;L&#39;installateur n&#39;aura peut-être pas ajouté le chemin à vos répertoires d&#39;include standard. Dans ce cas, il vous faudra configurer Visual Studio en allant dans Outils &amp;gt; Options &amp;gt; Projets et solutions &amp;gt; Répertoires de VC++. Dans le menu en haut à droite, sélectionnez &quot;Fichiers Include&quot; (pour les .h) ou &quot;Fichiers bibliothèques&quot; (pour les .lib/.dll), dépendamment de ce que vous voulez configurer.&lt;br /&gt;&lt;br /&gt;La meilleure façon de tester si Boost fonctionne est d&#39;y aller avec l&#39;exemple fournis par Boost (à noter que vous Boost.Regex n&#39;est pas installé par défaut avec l&#39;installateur, vous devrez donc avoir coché la case pour que cela fonctionne):&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;#include &amp;lt;boost/regex.hpp&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;    std::string line;&lt;br /&gt;    boost::regex pat( &quot;^Subject: (Re: |Aw: )*(.*)&quot; );&lt;br /&gt;&lt;br /&gt;    while (std::cin)&lt;br /&gt;    {&lt;br /&gt;        std::getline(std::cin, line);&lt;br /&gt;        boost::smatch matches;&lt;br /&gt;        if (boost::regex_match(line, matches, pat))&lt;br /&gt;            std::cout &amp;lt;&amp;lt; matches[2] &amp;lt;&amp;lt; std::endl;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Maintenant, Tcl. Vous pouvez l&#39;obtenir à cet endroit: &lt;a href=&quot;http://www.activestate.com/activetcl/&quot;&gt;http://www.activestate.com/activetcl/&lt;/a&gt; (cliquez sur le &quot;Download Now&quot;). Vous devrez ensuite (encore) configurer Visual Studio. À noter que cette fois-ci, pour que ça ne chie pas à l&#39;édition des liens, j&#39;ai du ajouter &quot;tcl85.lib&quot; aux propriétés de mon projet sous Éditeur de lien &amp;gt; Entrée &amp;gt; Dépendances supplémentaires.&lt;br /&gt;&lt;br /&gt;Ok, dernière étape: C++/Tcl lui même. Rendez-vous là: &lt;a href=&quot;http://sourceforge.net/projects/cpptcl/files/&quot;&gt;http://sourceforge.net/projects/cpptcl/files/&lt;/a&gt;. Bon, il faut ajouter cpptcl.cc et cpptcl.h à votre projet, et vous assurer que le répertoire details fournit avec C++/Tcl soit quelque part où le préprocesseur peut le trouver. Là, problème: le code ne compilait pas pour cause d&#39;ambiguïté entre std::exception et boost::exception. Il faut dire que le gars n&#39;a testé son code que sous GCC. Solution? Retirer le using namespace std en haut de cpptcl.cc, et ajouter std:: partout où c&#39;est nécessaire (en fait, à quelques endroits seulements, là où des std::string sont utilisées). &lt;br /&gt;&lt;br /&gt;Je suis allé ramasser le Hello World sur le site de C++/Tcl, et ça marche!&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;#include &quot;cpptcl.h&quot;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;using namespace Tcl;&lt;br /&gt;&lt;br /&gt;void hello()&lt;br /&gt;{&lt;br /&gt;     cout &amp;lt;&amp;lt; &quot;Hello C++/Tcl!&quot; &amp;lt;&amp;lt; endl;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;     interpreter i;&lt;br /&gt;     i.def(&quot;hello&quot;, hello);&lt;br /&gt;&lt;br /&gt;     string script = &quot;for {set i 0} {$i != 4} {incr i} { hello }&quot;;&lt;br /&gt;&lt;br /&gt;     i.eval(script);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Bon, je vais voir ce que ça donne. À suivre.</description><link>http://deliriumcorp.blogspot.com/2009/08/tclc-premiers-pas.html</link><author>noreply@blogger.com (Etienne de Martel)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8589498860624285456.post-6597383012189659061</guid><pubDate>Wed, 22 Jul 2009 23:50:00 +0000</pubDate><atom:updated>2009-07-22T21:11:23.036-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">c#</category><title>C#: Un IEqualityComparer&amp;lt;T&amp;gt; express</title><description>Java était (et est toujours, d&#39;ailleurs) un langage &quot;purement orienté objet&quot;. Quelle décision étrange. Non seulement Java est, selon moi, moins orienté objet que C++ (presque pas de contrôle sur la fin de vie d&#39;un objet, notamment), mais ça voulait également dire qu&#39;il ne pouvait faire rien d&#39;autre que de la POO. Pourtant, je me dis que du procédural, parfois, c&#39;est utile.&lt;br /&gt;&lt;br /&gt;C# répète à peu près les mêmes erreurs que Java pour la POO, mais compense en s&#39;ouvrant à d&#39;autres paradigmes. Dans sa version 3.0, C# a donc mis un pied (ou plutôt le gros orteil) dans le monde de la programmation fonctionnelle avec des lambda expressions et des expression trees (bon, on pouvait déjà faire ça depuis 1998 en C++ avec des templates, mais bel effort quand même). Et depuis sa toute première version, C# supporte un hybride entre méthodes et fonctions libres sous la forme de délégués (un pointeur déguisé sur une fonction, en fait). Bon, d&#39;accord, je pourrais également faire le parallèle avec C++, mais pourquoi taper sur quelqu&#39;un qui est à terre?&lt;br /&gt;&lt;br /&gt;Je sais pas pour vous, mais moi, écrire une classe pour ne l&#39;utiliser qu&#39;une seule fois, comme foncteur sans état en plus, je trouve ça lourd. C&#39;est d&#39;ailleurs pourquoi, en C++, je préfère les fonctions aux foncteurs lorsque c&#39;est possible: c&#39;est beaucoup moins verbeux (mais bon, une fonction n&#39;a pas d&#39;état, alors il faut parfois sortir les foncteurs). Alors bon, quand je vois, dans le .NET Framework, une méthode qui attend un IEqualityComparer&amp;lt;T&amp;gt;, je sacre. Pourquoi devrais-je implémenter une classe pour une fonctionnalité qui n&#39;existera que là? Ne serait-il pas plus simple de passer un délégué à la place? Martin Fowler n&#39;a-t-il pas dit que la généricité préventive était néfaste?&lt;br /&gt;&lt;br /&gt;J&#39;ai donc retroussé mes manches, et voici ce à quoi je suis arrivé:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;csharp&quot;&gt;&lt;br /&gt;public static class EqualityComparer&lt;br /&gt;{&lt;br /&gt;    private class DelegateComparer&amp;lt;T&amp;gt; : IEqualityComparer&amp;lt;T&amp;gt;&lt;br /&gt;    {&lt;br /&gt;        private readonly Func&amp;lt;T, T, bool&amp;gt; _equalityFunction; // prend deux T en paramètre et retourne un bool&lt;br /&gt;        private readonly Func&amp;lt;T, int&amp;gt; _hashCodeFunction; // prend un T en paramètre et retourne un int&lt;br /&gt;&lt;br /&gt;        public DelegateComparer(Func&amp;lt;T, T, bool&amp;gt; equalityFunction, Func&amp;lt;T, int&amp;gt; hashCodeFunction)&lt;br /&gt;        {&lt;br /&gt;            if (equalityFunction == null || hashCodeFunction == null)&lt;br /&gt;                throw new ArgumentNullException();&lt;br /&gt;            _equalityFunction = equalityFunction;&lt;br /&gt;            _hashCodeFunction = hashCodeFunction;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public bool Equals(T x, T y)&lt;br /&gt;        {&lt;br /&gt;            return _equalityFunction(x, y);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public int GetHashCode(T obj)&lt;br /&gt;        {&lt;br /&gt;            return _hashCodeFunction(obj);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static IEqualityComparer&amp;lt;T&amp;gt; Make&amp;lt;T&amp;gt;(Func&amp;lt;T, T, bool&amp;gt; EqualityFunction, Func&amp;lt;T, int&amp;gt; HashCodeFunction)&lt;br /&gt;    {&lt;br /&gt;        return new DelegateComparer&amp;lt;T&amp;gt;(EqualityFunction, HashCodeFunction);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Bon, quel intérêt? Eh bien, admettons (cet exemple utilise des lambdas, mais vous pourriez très bien passer des méthodes, tant qu&#39;elles ont la bonne signature):&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;csharp&quot;&gt;&lt;br /&gt;    var absComparer = EqualityComparer.Make&amp;lt;int&amp;gt;(&lt;br /&gt;                      (p1, p2) =&amp;gt; Math.Abs(p1) == Math.Abs(p2),&lt;br /&gt;                      p =&amp;gt; Math.Abs(p).GetHashCode());&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Et voilà, un IEqualityComparer&amp;lt;T&amp;gt; en une ligne (étalée sur plusieurs lignes pour plus de clarté)! C&#39;est tu pas wonderful?&lt;br /&gt;&lt;br /&gt;Dites-moi ce que vous en pensez. Comme toujours, ce n&#39;est pas final.</description><link>http://deliriumcorp.blogspot.com/2009/07/c-un-iequalitycomparer-express.html</link><author>noreply@blogger.com (Etienne de Martel)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8589498860624285456.post-6009967006342804664</guid><pubDate>Thu, 16 Jul 2009 00:07:00 +0000</pubDate><atom:updated>2009-07-17T20:33:48.205-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">c++</category><title>C++: Implémenter un getline_iterator</title><description>&lt;b&gt;EDIT 17/07/2009: &lt;/b&gt; Suite à un commentaire de mon bon ami Andy, j&#39;ai apporté quelques modifications au code.&lt;br /&gt;&lt;br /&gt;Tous ceux qui se sont amusés un tant soit peu avec les flux d&#39;entrée en C++ ont probablement déjà entendu parler des std::istream_iterator. Ils permettent de parcourir un flux entrée (une instance d&#39;une classe héritant de std::istream) comme si c&#39;était une séquence. Un appel à l&#39;opérateur ++ d&#39;un tel flux revient à utiliser l&#39;opérateur &amp;gt;&amp;gt; sur le flux, et on peut ensuite utiliser les opérateurs * et -&amp;gt; pour accéder à l&#39;élément précédemment lu. Un std::istream_iterator est unidirectionnel (on ne peut qu&#39;avancer dans le flux) et en lecture seule (évidemment, puisque l&#39;on s&#39;en sert pour lire d&#39;un flux). Un std::istream_iterator constant n&#39;a donc pas de sens.&lt;br /&gt;&lt;br /&gt;L&#39;idéal est de passer par un exemple. Imaginons que nous voulons lire, dans un fichier, un ensemble de nombres entiers pour ensuite les insérer dans un vecteur. La première solution serait d&#39;avoir recours à une boucle dans laquelle on insère les entiers lus dans le vecteur avec push_back(). Ou bien, on peut également faire la même chose en une ligne en mélangeant std::copy, un std::istream_iterator et un std::back_inserter:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;std::ifstream file(&quot;hello.txt&quot;);&lt;br /&gt;std::vector&amp;lt;int&amp;gt; v;&lt;br /&gt;std::copy(std::istream_iterator&amp;lt;int&amp;gt;(file), std::istream_iterator&amp;lt;int&amp;gt;(), std::back_inserter(v));&lt;br /&gt;std::cout &amp;lt;&amp;lt; v.size();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Une petite explication s&#39;impose. istream_iterator possède deux constructeurs: l&#39;un deux reçois un flux d&#39;entrée (std::istream) à parcourir. Le second (celui qui ne prend pas de paramètres) représente un flux invalide. Ainsi, dans notre exemple précédent, si le flux tombe dans un état invalide (la fin du fichier, par exemple), alors les deux itérateurs deviendront égaux, permettant de sortir de la boucle.&lt;br /&gt;On copie donc du début (premier paramètre) à la fin (second paramètre) du flux, en envoyant les éléments à un std::back_inserter, lequel ne fait que passer l&#39;élément reçu à la méthode push_back() du vecteur.&lt;br /&gt;&lt;br /&gt;Malheureusement, std::istream_iterator utilise &amp;gt;&amp;gt; pour lire les données. Mais que se passe-t-il si l&#39;on veut lire avec la si utile fonction std::getline()?&lt;br /&gt;&lt;br /&gt;D&#39;où l&#39;idée que j&#39;ai eu de coder un getline_iterator. Il fonctionne exactement comme un std::istream_iterator, mais utilise std::getline() plutôt que l&#39;opérateur &amp;gt;&amp;gt; pour lire les données.&lt;br /&gt;&lt;hr /&gt;On commence donc par inclure les fichiers nécessaires: iterator, string et istream.&lt;br /&gt;La classe est une classe template, spécialisée d&#39;après un certain type de caractères. std::getline() ne lit en effet que des chaînes de caractère, il est donc inutile de la rendre plus générique. On peut également spécifier des traits de caractère, et les traits de base du type de caractère spécifié sont utilisés par défaut.&lt;br /&gt;&lt;br /&gt;La classe hérite de std::iterator, et spécifie trois choses: basic_getline_iterator est un itérateur d&#39;entrée (input_iterator), il lit des éléments de type std::basic_string&amp;lt;CharType, Traits&amp;gt;, et la distance entre les éléments est de type std::basic_string&amp;lt;CharType, Traits&amp;gt;::size_type (la même que pour une string, donc).&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;#ifndef GETLINE_ITERATOR_H&lt;br /&gt;#define GETLINE_ITERATOR_H&lt;br /&gt;&lt;br /&gt;#include &amp;lt;iterator&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;#include &amp;lt;istream&amp;gt;&lt;br /&gt;&lt;br /&gt;template&amp;lt;class CharType, class Traits = std::char_traits&amp;lt;CharType&amp;gt; &amp;gt;&lt;br /&gt;class basic_getline_iterator : public std::iterator&amp;lt;std::input_iterator_tag, &lt;br /&gt;                                                    std::basic_string&amp;lt;CharType, Traits&amp;gt;, &lt;br /&gt;                                                    typename std::basic_string&amp;lt;CharType, Traits&amp;gt;::size_type&amp;gt;&lt;br /&gt;{&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Pour garantir l&#39;intéropérabilité avec les algorithmes et classes de la STL, on définit quelques typedefs. Seuls les cinq premiers sont obligatoires. Le dernier, stream_type, est là pour simplifier la syntaxe, plus loin. Je l&#39;ai laissé en public car je ne voyais pas vraiment la nécessité de le cacher.&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;public:&lt;br /&gt;    typedef std::input_iterator_tag iterator_category;&lt;br /&gt;    typedef typename std::basic_string&amp;lt;CharType, Traits&amp;gt; value_type;&lt;br /&gt;    typedef typename std::basic_string&amp;lt;CharType, Traits&amp;gt;::size_type distance;&lt;br /&gt;    typedef value_type &amp;amp; reference;&lt;br /&gt;    typedef value_type * pointer;&lt;br /&gt;&lt;br /&gt;    typedef typename std::basic_istream&amp;lt;CharType, Traits&amp;gt; stream_type;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;On a trois attributs: l&#39;élément en lu lors du dernier appel à l&#39;opérateur ++ (un basic_string), un pointeur sur le flux (nous verrons pourquoi un pointeur dans quelques instants) et le caractère faisant office de séparateur (utile pour std::getline()).&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;private:&lt;br /&gt;    value_type _current;&lt;br /&gt;    stream_type * _stream;&lt;br /&gt;    const CharType _separator;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Le premier constructeur (celui qui représente un flux invalide) ne fait qu&#39;assigner 0 au pointeur, et \0 au séparateur (le séparateur doit être initialisé puisqu&#39;il est constant). Le second constructeur reçoit une référence sur un std::istream (tous les flux sont incopiables, donc une référence est obligatoire), et assigne l&#39;adresse de ce flux au pointeur. Un paramètre optionnel peut également être passé pour faire office de séparateur. Par défaut, il s&#39;agit du retour de ligne (ça ne s&#39;appelle pas &quot;getline&quot; pour rien).&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;public:&lt;br /&gt;    basic_getline_iterator() : _stream(0), _separator(&#39;\0&#39;) {}&lt;br /&gt;    basic_getline_iterator(stream_type &amp;amp; stream, char separator = &#39;\n&#39;) : _stream(&amp;amp;stream), _separator(separator) {}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;L&#39;opérateur++ est disponible en version préfixée (première version) et postfixée (seconde version). La version préfixée appelle std::getline en passant les paramètres requis, puis teste la valeur de retour de la fonction. std::getline() retourne ne effet le flux passé comme premier paramètre. Ce flux peut être convertit implicitement en void *. Si le pointeur est nul, alors le flux est invalide. Donc, s&#39;il est invalide, on assigne 0 au pointeur. Suite à un commentaire, j&#39;ai décidé d&#39;ajouter un test à l&#39;opérateur ++ pour empêcher un plantage lamentable si quelqu&#39;un venait à incrémenter le pointeur alors que l&#39;itérateur est invalide.&lt;br /&gt;La version postfixée créée une copie, appelle la version préfixée, puis retourne la copie.&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;    basic_getline_iterator operator++() throw()&lt;br /&gt;    {&lt;br /&gt;        if(_stream)&lt;br /&gt;        {&lt;br /&gt;            if(!std::getline(*_stream, _current, _separator))&lt;br /&gt;                _stream = 0;&lt;br /&gt;        }&lt;br /&gt;        return *this;&lt;br /&gt;    }&lt;br /&gt;    basic_getline_iterator operator++(int) throw()&lt;br /&gt;    {&lt;br /&gt;        basic_getline_iterator it(*this);&lt;br /&gt;        operator++();&lt;br /&gt;        return it;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Une simple comparaison de pointeurs. Ainsi, si les deux itérateurs représentent des flux invalides, ils seront considérés comme égaux.&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;    bool operator==(const basic_getline_iterator &amp;amp;it) const throw()&lt;br /&gt;    {&lt;br /&gt;        return _stream == it._stream;&lt;br /&gt;    }&lt;br /&gt;    bool operator!=(const basic_getline_iterator &amp;amp;it) const throw()&lt;br /&gt;    {&lt;br /&gt;        return !(*this == it);&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Déréférencer l&#39;itérateur ne fait que retourner une référence (ou un pointeur) sur l&#39;élément précédemment lu.&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;    const value_type &amp;amp; operator *() const throw()&lt;br /&gt;    {&lt;br /&gt;        return _current;&lt;br /&gt;    }&lt;br /&gt;    const value_type * operator-&amp;gt;() const throw()&lt;br /&gt;    {&lt;br /&gt;        return &amp;amp;_current;&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Pour finir, on offre deux typedefs correspondants aux deux utilisations principales de basic_getline_iterator. Voilà!&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;typedef basic_getline_iterator&amp;lt;char&amp;gt;    getline_iterator;&lt;br /&gt;typedef basic_getline_iterator&amp;lt;wchar_t&amp;gt; wgetline_iterator;&lt;br /&gt;#endif&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Rien de mieux qu&#39;un exemple:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&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;string&amp;gt;&lt;br /&gt;#include &amp;lt;iterator&amp;gt;&lt;br /&gt;#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;#include &amp;lt;vector&amp;gt;&lt;br /&gt;#include &amp;quot;getline_iterator.h&amp;quot;&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;    // lire les lignes d&#39;un fichier puis les insérer dans un vecteur&lt;br /&gt;    std::ifstream file(&amp;quot;test.txt&amp;quot;);&lt;br /&gt;    std::vector&amp;lt;std::string&amp;gt; v;&lt;br /&gt;    std::copy(getline_iterator(file), getline_iterator(), std::back_inserter(v));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Cet itérateur est encore en développement, et il se peut que je revienne apporter des modifications (notamment la const-correctness). À suivre.</description><link>http://deliriumcorp.blogspot.com/2009/07/c-implementer-un-getlineiterator.html</link><author>noreply@blogger.com (Etienne de Martel)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8589498860624285456.post-4500771110827234058</guid><pubDate>Sun, 17 May 2009 18:59:00 +0000</pubDate><atom:updated>2009-07-15T20:05:27.409-04:00</atom:updated><title>C#: Utiliser un BitVector32 pour représenter des flags</title><description>Disons que vous avez une base de données contenant une table User, contenant les informations des utilisateurs de votre site. Vous voulez probablement représenter un ensembles d&#39;options sous la forme de booléens (ENUM ou BOOLEAN sous MySQL, bit sous SQL Server, etc.). Le problème avec cette approche, est que si vous voulez ajouter des options additionnelles, vous devrez modifier la structure de la base de données. Et je ne sais pas pour vous, mais je ne suis pas très chaud à l&#39;idée de faire des ALTER TABLE sur une BD &lt;i&gt;live&lt;/i&gt;. Vous pouvez donc ajouter une table d&#39;options, et une table de liaison reliant une option à un utilisateur (avec probablement la valeur de cette option). Mais c&#39;est plutôt lourd. Une solution au problème serait donc d&#39;utiliser une colonne, d&#39;un type supportant un entier 32 bits (INT sous MySQL, int sous SQL Server, etc.), de votre table User, pour stocker des flags. À coup de manipulation de bits, on pourrait donc avoir 32 options différentes avec un seul int. Sauf que les manipulation de bits, c&#39;est complexe. Et c&#39;est l&#39;enfer à maintenir.&lt;br /&gt;&lt;br /&gt;C&#39;est alors que j&#39;ai découvert le struct BitVector32, du namespace System.Collections.Specialized. Il permet de représenter un int (System.Int32) comme un ensemble de booléens. Il a également d&#39;autre utilisations, mais je ne les couvrirai pas ici. Pour plus d&#39;informations, consultez &lt;a href=&quot;http://msdn.microsoft.com/en-us/library/system.collections.specialized.bitvector32%28loband%29.aspx&quot;&gt;MSDN&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Commençons par définir une énumération contenant les divers flags qui s&#39;appliqueront à notre utilisateur:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;csharp&quot;&gt;&lt;br /&gt;[Flags]&lt;br /&gt;public enum UserFlags&lt;br /&gt;{&lt;br /&gt; IsActive = 1,&lt;br /&gt; IsBanned = 2,&lt;br /&gt; ShowEmail = 4&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Il est important que chaque élément de l&#39;énumération ait pour valeur une puissance de 2. De même, l&#39;attribut Flags n&#39;est pas obligatoire, mais permettrait à notre énumération d&#39;être utilisée comme flags dans un contexte &quot;à la C&quot;, avec les valeurs séparées par des pipes (|).&lt;br /&gt;&lt;br /&gt;Puis, créons une petite classe User. Elle pourrait être mappée à l&#39;aide d&#39;un ORM comme NHibernate ou SubSonic.&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;csharp&quot;&gt;&lt;br /&gt;public class User&lt;br /&gt;{&lt;br /&gt; public string Username { get; private set; }&lt;br /&gt; public string Password { get; private set; }&lt;br /&gt; public string Email { get; private set; }&lt;br /&gt; private BitVector32 _flags;&lt;br /&gt;&lt;br /&gt; public User(string username, string password, string email)&lt;br /&gt; {&lt;br /&gt;     Username = username;&lt;br /&gt;     Password = password;&lt;br /&gt;     Email = email;&lt;br /&gt;     _flags = new BitVector32();&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Puis, on ajoute des propriétés à notre classe User:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;csharp&quot;&gt;&lt;br /&gt;public bool IsActive&lt;br /&gt;{&lt;br /&gt;   get { return _flags[(int)UserFlags.IsActive]; }&lt;br /&gt;   set { _flags[(int)UserFlags.IsActive] = value; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public bool IsBanned&lt;br /&gt;{&lt;br /&gt;   get { return _flags[(int)UserFlags.IsBanned]; }&lt;br /&gt;   set { _flags[(int)UserFlags.IsBanned] = value; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public bool ShowEmail&lt;br /&gt;{&lt;br /&gt;   get { return _flags[(int)UserFlags.ShowEmail]; }&lt;br /&gt;   set { _flags[(int)UserFlags.ShowEmail] = value; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Voilà. L&#39;usage est entièrement transparent; du côté du code client, on a l&#39;impression de manipuler des booléens, alors qu&#39;en réalité, tout se passe dans un int.&lt;br /&gt;&lt;br /&gt;On peut également, pour des fins de tests, produire une propriété RawFlags qui retournera la valeur entière de notre BitVector32:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;csharp&quot;&gt;&lt;br /&gt; public int RawFlags&lt;br /&gt; {&lt;br /&gt;     get&lt;br /&gt;     {&lt;br /&gt;         return _flags.Data;&lt;br /&gt;     }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;Lorsqu&#39;il viendra le temps d&#39;enregistrer les flags dans la BD, il suffira alors de prendre la valeur contenue dans la propriété Data du vecteur. On peut effectuer l&#39;opération inverse en utilisant le constructeur de BitVector32 qui prend un int.&lt;br /&gt;&lt;br /&gt;Voilà!</description><link>http://deliriumcorp.blogspot.com/2009/05/c-utiliser-un-bitvector32-pour.html</link><author>noreply@blogger.com (Unknown)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8589498860624285456.post-6296870094582327485</guid><pubDate>Tue, 28 Apr 2009 02:11:00 +0000</pubDate><atom:updated>2009-04-27T22:23:31.259-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">html</category><title>Remarque sur les champs disabled</title><description>Voici ce que le W3C a à dire sur les champs de formulaire dit &quot;disabled&quot;:&lt;br /&gt;&lt;p style=&quot;font-style: italic;&quot;&gt;When set, the disabled attribute has the following effects on an element:&lt;br /&gt;- Disabled controls do not receive focus.&lt;br /&gt;- Disabled controls are skipped in tabbing navigation.&lt;br /&gt;- Disabled controls cannot be successful.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;Que signifie ce terme &quot;successful&quot;? Eh bien, toujours d&#39;après le W3C:&lt;br /&gt;&lt;p style=&quot;font-style: italic;&quot;&gt;A successful control is &quot;valid&quot; for submission. Every successful control has its control name paired with its current value as part of the submitted form data set. A successful control must be defined within a FORM element and must have a control name.&lt;/p&gt;&lt;br /&gt;En clair: d&#39;après le standard, les champs &quot;disabled&quot; ne sont pas envoyés au serveur. Si vous tenez à bloquer l&#39;accès à un contrôle mais que vous voulez quand même qu&#39;il soit envoyé au serveur, il y a deux choix: du JavaScript, ou encore l&#39;attribut readonly:&lt;br /&gt;&lt;p style=&quot;font-style: italic;&quot;&gt;When set, the readonly attribute has the following effects on an element:&lt;br /&gt;- Read-only elements receive focus but cannot be modified by the user.&lt;br /&gt;- Read-only elements are included in tabbing navigation.&lt;br /&gt;- Read-only elements may be successful.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;Jamais je n&#39;aurais cru que le W3C m&#39;aiderait à résoudre un bogue...</description><link>http://deliriumcorp.blogspot.com/2009/04/remarque-sur-les-champs-disabled.html</link><author>noreply@blogger.com (Unknown)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8589498860624285456.post-2146433826628063481</guid><pubDate>Tue, 17 Mar 2009 01:32:00 +0000</pubDate><atom:updated>2009-07-14T16:04:34.838-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">c#</category><title>C#: Récupérer les éléments d&#39;une énumération</title><description>J&#39;ai récemment voulu peupler les données d&#39;un DropDownList ASP.NET avec les éléments contenus dans une énumération. Avec un peu de recherches, j&#39;ai découvert la classe utilitaire Enum permettant d&#39;obtenir des informations intéressantes sur une énumération. J&#39;ai donc codé une méthode pour retourner sous la forme d&#39;un Dictionnary&lt;int, string&gt; les éléments d&#39;une énumération donnée:&lt;br /&gt;&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;csharp&quot;&gt;&lt;br /&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;&lt;br /&gt;namespace Util&lt;br /&gt;{&lt;br /&gt;    public static class EnumUtils&lt;br /&gt;    {&lt;br /&gt;        /// &amp;lt;summary&amp;gt;&lt;br /&gt;        /// Obtient les éléments composant une énumération&lt;br /&gt;        /// &amp;lt;/summary&amp;gt;&lt;br /&gt;        /// &amp;lt;typeparam name=&amp;quot;TEnum&amp;quot;&amp;gt;Le type de l&#39;énumération&amp;lt;/typeparam&amp;gt;&lt;br /&gt;        /// &amp;lt;exception cref=&amp;quot;ArgumentException&amp;quot;&amp;gt;Lancée si TEnum n&#39;est pas une énumération&amp;lt;/exception&amp;gt;&lt;br /&gt;        /// &amp;lt;returns&amp;gt;Un dictionnaire avec comme clé la valeur entière d&#39;un élément et comme valeur, son nom&amp;lt;/returns&amp;gt;&lt;br /&gt;        public static IDictionary&amp;lt;int, string&amp;gt; GetEnumElements&amp;lt;TEnum&amp;gt;()&lt;br /&gt;        {&lt;br /&gt;            &lt;br /&gt;            var type = typeof(TEnum);&lt;br /&gt;            if (!type.IsEnum)&lt;br /&gt;                throw new ArgumentException(&amp;quot;Type must be an enum type&amp;quot;);&lt;br /&gt;&lt;br /&gt;            var names = Enum.GetNames(type);&lt;br /&gt;            var values = Enum.GetValues(type);&lt;br /&gt;&lt;br /&gt;            var elements = new Dictionary&amp;lt;int, string&amp;gt;();&lt;br /&gt;            for (int i = 0; i &amp;lt; names.Length; ++i)&lt;br /&gt;            {&lt;br /&gt;                elements.Add((int)values.GetValue(i), names[i]);&lt;br /&gt;            }&lt;br /&gt;            return elements;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;La présence du mot clé &lt;b&gt;var&lt;/b&gt; force l&#39;utilisation d&#39;un compilateur respectant la norme 3.0 du langage, mais il suffit de retirer ceci pour permettra la compatibilité avec la version 2.0.</description><link>http://deliriumcorp.blogspot.com/2009/03/c-recuperer-les-elements-dune.html</link><author>noreply@blogger.com (Unknown)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8589498860624285456.post-3349476170375676147</guid><pubDate>Tue, 20 Jan 2009 00:59:00 +0000</pubDate><atom:updated>2009-01-19T22:06:07.924-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">c++</category><category domain="http://www.blogger.com/atom/ns#">v8</category><title>V8: Insérer un pointeur C++ dans un objet JS</title><description>Victoire! Je me suis débarrassé de cet ignoble objet global et j&#39;ai en même temps appris l&#39;existence du type v8::External, qui est un enrobage autour d&#39;un void *.&lt;br /&gt;&lt;br /&gt;J&#39;ai tout d&#39;abord commencé par définir un typedef pour éviter une verbosité excessive:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;typedef TestCollection&amp;lt;std::string, int&amp;gt; Collection;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Commençons d&#39;abord par le main:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;    // La collection&lt;br /&gt;    Collection testCollection;&lt;br /&gt;    v8::HandleScope handleScope;&lt;br /&gt;    // On créé l&#39;objet global&lt;br /&gt;    v8::Handle&amp;lt;v8::ObjectTemplate&amp;gt; global = v8::ObjectTemplate::New();&lt;br /&gt;    // On créé la fonction print&lt;br /&gt;    global-&amp;gt;Set(&amp;quot;print&amp;quot;, v8::FunctionTemplate::New(print));&lt;br /&gt;    // On créé le template de la collection&lt;br /&gt;    v8::Local&amp;lt;v8::ObjectTemplate&amp;gt; collectionTemplate = v8::ObjectTemplate::New();&lt;br /&gt;    // On créé les deux méthodes du template&lt;br /&gt;    collectionTemplate-&amp;gt;Set(&amp;quot;getObjectById&amp;quot;, v8::FunctionTemplate::New(getObjectById));&lt;br /&gt;    collectionTemplate-&amp;gt;Set(&amp;quot;setObject&amp;quot;, v8::FunctionTemplate::New(setObject));&lt;br /&gt;    // On informe le template qu&#39;il aura un champ interne &lt;br /&gt;    // (si on ne le fait pas, on aura un débordement de tableau plus tard)&lt;br /&gt;    collectionTemplate-&amp;gt;SetInternalFieldCount(1);&lt;br /&gt;    // On créé le contexte&lt;br /&gt;    v8::Handle&amp;lt;v8::Context&amp;gt; context = v8::Context::New(0, global); &lt;br /&gt;    // On créé le script&lt;br /&gt;    JSScript script(&amp;quot;script.js&amp;quot;, context); &lt;br /&gt;    // On instancie la collection à partir du template&lt;br /&gt;    v8::Local&amp;lt;v8::Object&amp;gt; collection = collectionTemplate-&amp;gt;NewInstance(); &lt;br /&gt;    // On assigne un pointeur sur testCollection à la collection pour qu&#39;on puisse y accéder plus tard&lt;br /&gt;    collection-&amp;gt;SetInternalField(0, v8::External::New(&amp;amp;testCollection));      &lt;br /&gt;    // On assigne la collection comme appartenant à l&#39;objet global&lt;br /&gt;    context-&amp;gt;Global()-&amp;gt;Set(v8::String::New(&amp;quot;collection&amp;quot;), collection);&lt;br /&gt;    // On exécute le script&lt;br /&gt;    script.run();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;On remarque d&#39;abord l&#39;objet global et la fonction print(). Puis, le template de la collection. Or, ça s&#39;arrête là. J&#39;ai en effet réalisé que l&#39;on n&#39;était pas obligé d&#39;utiliser le template comme objet. On pourrait voir un template comme une classe: on le créé, on définit des méthodes, puis on instancie à l&#39;aide de NewInstance().&lt;br /&gt;Ah, NewInstance(). Cette méthode m&#39;a donnée du fil à retordre. Originellement, elle causait une erreur de segmentation, jusqu&#39;à ce que je réalise qu&#39;on devait obligatoirement créer un Context et un ContextScope avant. Un objet ne peut en effet exister que dans un contexte: on ne peut créer un objet &quot;dans le vide&quot;.&lt;br /&gt;Une fois l&#39;objet instancié à l&#39;aide de NewInstance(), on peut lui assigner divers méthodes ou attributs à l&#39;aide de Set, ou des données internes (similaires en utilisation à des attributs privés) à l&#39;aide de ce qu&#39;on appelle un &quot;internal field&quot;. Un champ interne est un attribut qui ne sera pas accessible par le script. On peut donc s&#39;en servir pour stocker diverses informations. Ici, je m&#39;en sert pour stocker un External, qui contiendra un pointeur sur la collection. Finalement, on déclare collection comme un objet appartenant à l&#39;objet global. Remarquez la syntaxe différente: on assigne pas des objets comme on assigne des templates. L&#39;effet est le même, par contre.&lt;br /&gt;&lt;br /&gt;Mais comment utiliser ce pointeur? Voici la fonction setObject():&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;v8::Handle&amp;lt;v8::Value&amp;gt; setObject(const v8::Arguments &amp;amp;args)&lt;br /&gt;{&lt;br /&gt;    if(args.Length() == 2)&lt;br /&gt;    { &lt;br /&gt;        // args.Holder() retourne l&#39;objet possédant la fonction: dans ce cas précis, l&#39;objet de collection&lt;br /&gt;        // On va donc chercher le External dans l&#39;objet à l&#39;aide de GetInternalField()&lt;br /&gt;        // L&#39;appel à la méthode Cast est nécessaire, car GetInternalField() retourne un Object&lt;br /&gt;        // alors que nous voulons un External&lt;br /&gt;        v8::Local&amp;lt;v8::External&amp;gt; external = v8::Local&amp;lt;v8::External&amp;gt;::Cast(args.Holder()-&amp;gt;GetInternalField(0));&lt;br /&gt;        // Puis, on prend le pointeur contenu dans le External. &lt;br /&gt;        // Celui-ci sera un void *, alors un cast est nécessaire&lt;br /&gt;        Collection * collection = static_cast&amp;lt;Collection *&amp;gt;(external-&amp;gt;Value());&lt;br /&gt;        // Le reste est identique&lt;br /&gt;        v8::HandleScope handleScope;&lt;br /&gt;        v8::String::Utf8Value key(args[0]);&lt;br /&gt;        v8::Local&amp;lt;v8::Value&amp;gt; value(args[1]);&lt;br /&gt;        collection-&amp;gt;setObject(*key, value-&amp;gt;Int32Value());&lt;br /&gt;    }&lt;br /&gt;    return v8::Undefined();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;getObjectById() est similaire. L&#39;important ce situe dans les premières lignes du if: le reste est inchangé (ou presque: on utilise maintenant le pointeur sur l&#39;objet).&lt;br /&gt;&lt;br /&gt;Voilà!&lt;br /&gt;&lt;br /&gt;Prochaine étape: faire en sorte que getObjectById() retourne des objets JS complexes plutôt que des entiers. Cela me permettra d&#39;expérimenter les accesseurs.&lt;br /&gt;&lt;br /&gt;Comme toujours, j&#39;attends vos commentaires.&lt;br /&gt;&lt;br /&gt;Ah, oui, j&#39;en profite pour laisser un lien sur des benchmarks des divers moteurs JavaScript sur le marché: &lt;br /&gt;&lt;a href=&quot;http://ejohn.org/blog/javascript-performance-rundown/&quot;&gt;JavaScript Performance Rundown&lt;/a&gt;.&lt;br /&gt;Comme vous pouvez le voir, IE ne joue pas dans la même ligue que le reste.</description><link>http://deliriumcorp.blogspot.com/2009/01/v8-insrer-un-pointeur-c-dans-un-objet.html</link><author>noreply@blogger.com (Unknown)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8589498860624285456.post-763589012354256944</guid><pubDate>Sun, 18 Jan 2009 00:27:00 +0000</pubDate><atom:updated>2009-01-18T14:53:14.034-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">c++</category><category domain="http://www.blogger.com/atom/ns#">v8</category><title>V8: faire paraître un objet C++ comme un objet JS</title><description>À coup d&#39;essais et d&#39;erreurs, j&#39;y suis arrivé! Enfin, presque. J&#39;utilise, pour faire simple, un objet global. Je sais, c&#39;est laid, mais ce n&#39;est que pour des fins de tests. &lt;br /&gt;&lt;br /&gt;Bon! Il faut d&#39;abord savoir que V8 fonctionne à coup de callbacks. Et un callback V8, pour une fonction (les objets utilisent des &quot;accesseurs&quot; et des &quot;intercepteurs&quot;, qui ont une signature différente), eh bien, c&#39;est une fonction qui a le prototype suivant (remplacez &quot;callback&quot; par le nom de votre choix):&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;v8::Handle&amp;lt;v8::Value&amp;gt; callback(const v8::Arguments &amp;args);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Un tel prototype nous apprend deux choses:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Une fonction JS peut prendre un nombre arbitraire de paramètres (args encapsulant en fait un conteneur quelconque)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Une fonction JS retourne toujours une valeur. Il n&#39;existe pas de fonction &quot;void&quot;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;M&#39;inspirant donc de l&#39;exemple shell.cc, j&#39;ai créé une fonction print qui sera appelée lorsqu&#39;un script appellera une fonction JS nommée print:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;v8::Handle&amp;lt;v8::Value&amp;gt; print(const v8::Arguments &amp;amp;args)&lt;br /&gt;{&lt;br /&gt;    if(args.Length() == 1) // On ne veut qu&#39;un seul paramètre&lt;br /&gt;    {&lt;br /&gt;        v8::HandleScope handleScope; // On définit une portée pour nos Handle&lt;br /&gt;        v8::String::Utf8Value str(args[0]); // On obtient la valeur du premier paramètre&lt;br /&gt;        std::cout &amp;lt;&amp;lt; *str &amp;lt;&amp;lt; std::endl; // On l&#39;affiche ainsi qu&#39;un retour de ligne&lt;br /&gt;    }&lt;br /&gt;    return v8::Undefined(); // Les fonctions &amp;quot;void&amp;quot; sont en fait des fonctions qui retournent undefined&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Cette fonction permettra donc à quelqu&#39;un d&#39;envoyer des données dans cout à travers un script JS.&lt;br /&gt;&lt;br /&gt;Voici le concept: on veut créer un objet JS global nommé &quot;collection&quot; qui supportera deux méthodes: getObjectById(string), qui retourne un entier correspondant à la clé passée en paramètre (ou null si la clé n&#39;existe pas), et setObject(string, int) qui assigne une valeur à une clé (ou la créé si la clé n&#39;existe pas).&lt;br /&gt;&lt;br /&gt;J&#39;ai donc commencé par créer une classe TestCollection (un enrobage autour de std::map, en fait):&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;#include &amp;lt;map&amp;gt;&lt;br /&gt;#include &amp;lt;exception&amp;gt;&lt;br /&gt;&lt;br /&gt;template&amp;lt;class K, class V&amp;gt;&lt;br /&gt;class TestCollection&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;    typedef K key_type;&lt;br /&gt;    typedef V value_type;&lt;br /&gt;private:&lt;br /&gt;    std::map&amp;lt;key_type, value_type&amp;gt; collection_;&lt;br /&gt;public:&lt;br /&gt;    value_type getObjectById(const key_type &amp;amp; id) const&lt;br /&gt;    {&lt;br /&gt;        std::map&amp;lt;key_type, value_type&amp;gt;::const_iterator itt = collection_.find(id);&lt;br /&gt;        if(itt != collection_.end())&lt;br /&gt;        {&lt;br /&gt;            return itt-&amp;gt;second;&lt;br /&gt;        }&lt;br /&gt;        else&lt;br /&gt;        {&lt;br /&gt;            throw std::exception(&amp;quot;Object not found&amp;quot;);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    void setObject(key_type id, value_type val)&lt;br /&gt;    {&lt;br /&gt;        collection_[id] = val;&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Définissons nous ensuite un objet global (oui, je sais, c&#39;est laid):&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;TestCollection&amp;lt;std::string, int&amp;gt; collection;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Puis, créons les deux callbacks:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;v8::Handle&amp;lt;v8::Value&amp;gt; setObject(const v8::Arguments &amp;amp;args)&lt;br /&gt;{&lt;br /&gt;    if(args.Length() == 2)&lt;br /&gt;    {&lt;br /&gt;        v8::HandleScope handleScope;&lt;br /&gt;        v8::String::Utf8Value key(args[0]); // La clé, c-a-d une string&lt;br /&gt;        v8::Local&amp;lt;v8::Value&amp;gt; value(args[1]); // La valeur, c-a-d un int&lt;br /&gt;        collection.setObject(*key, value-&amp;gt;Int32Value()); // On appelle la méthode setObject de l&#39;objet&lt;br /&gt;    }&lt;br /&gt;    return v8::Undefined();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;v8::Handle&amp;lt;v8::Value&amp;gt; getObjectById(const v8::Arguments &amp;amp;args)&lt;br /&gt;{&lt;br /&gt;    if(args.Length() == 1)&lt;br /&gt;    {&lt;br /&gt;        v8::HandleScope handleScope;&lt;br /&gt;        v8::String::Utf8Value str(args[0]); // On va chercher la clé&lt;br /&gt;        try&lt;br /&gt;        {&lt;br /&gt;            const std::string key(*str); // On créé une std::string à partir de la clé&lt;br /&gt;            int i = collection.getObjectById(key); // On va chercher la valeur&lt;br /&gt;            return v8::Int32::New(i); // On la retourne&lt;br /&gt;        }&lt;br /&gt;        catch(std::exception e)&lt;br /&gt;        {&lt;br /&gt;            // L&#39;objet n&#39;a pas été trouvé, on affiche le message&lt;br /&gt;            std::cout &amp;lt;&amp;lt; e.what();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    return v8::Null();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ces deux fonctions ne sont en fait que des interfaces pour les méthodes du vrai objet.&lt;br /&gt;&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;cpp&quot;&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;    v8::HandleScope handleScope;&lt;br /&gt;     // On créé l&#39;objet global&lt;br /&gt;    v8::Handle&amp;lt;v8::ObjectTemplate&amp;gt; global = v8::ObjectTemplate::New();&lt;br /&gt;    // On créé la fonction print&lt;br /&gt;    global-&amp;gt;Set(&amp;quot;print&amp;quot;, v8::FunctionTemplate::New(print));&lt;br /&gt;    // On créé la collection&lt;br /&gt;    v8::Handle&amp;lt;v8::ObjectTemplate&amp;gt; collection = v8::ObjectTemplate::New(); &lt;br /&gt;     // On créé les deux méthodes de la collection&lt;br /&gt;    collection-&amp;gt;Set(&amp;quot;getObjectById&amp;quot;, v8::FunctionTemplate::New(getObjectById));&lt;br /&gt;    collection-&amp;gt;Set(&amp;quot;setObject&amp;quot;, v8::FunctionTemplate::New(setObject));         &lt;br /&gt;    // On assigne la collection comme appartenant à global&lt;br /&gt;    global-&amp;gt;Set(&amp;quot;collection&amp;quot;, collection); &lt;br /&gt;    // On créé le contexte en spécifiant l&#39;objet global&lt;br /&gt;    v8::Handle&amp;lt;v8::Context&amp;gt; context = v8::Context::New(0, global); &lt;br /&gt;    // On exécute le script&lt;br /&gt;    JSScript script(&amp;quot;script.js&amp;quot;, context); &lt;br /&gt;    script.run();&lt;br /&gt;&lt;br /&gt;    system(&amp;quot;pause&amp;quot;);&lt;br /&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Tout d&#39;abord, l&#39;objet global. Lorsque l&#39;on appelle une fonction libre ou que l&#39;on accède à une variable globale, en JS, en fait, on appelle une méthode ou on accède à un attribut de l&#39;objet global. Cet objet est créé comme n&#39;importe quel objet, à l&#39;aide d&#39;un ObjectTemplate.&lt;br /&gt;Même chose pour l&#39;objet collection: celui-ci est en fait un ObjectTemplate auquel on ajoute deux méthodes (lesquelles sont des FunctionTemplate) à l&#39;aide de la méthode Set. On ajoute ensuite collection à global à l&#39;aide de Set, et on créé le contexte en informant celui-ci qu&#39;il devra utiliser un objet global déja créé (par défaut, il créé un objet vide).&lt;br /&gt;Voilà.&lt;br /&gt;Ah, oui, JSScript est une petite classe que j&#39;ai créée pour automatiser la logique de création et d&#39;exécution d&#39;un script. Son contenu est trivial alors je ne la dévoilerai pas ici.&lt;br /&gt;&lt;br /&gt;Pour ceux que ça intéresse, voici le contenu de script.js:&lt;br /&gt;&lt;pre name=&quot;code&quot; class=&quot;js&quot;&gt;&lt;br /&gt;collection.setObject(&amp;quot;test&amp;quot;, 2);&lt;br /&gt;collection.setObject(&amp;quot;test2&amp;quot;, collection.getObjectById(&amp;quot;test&amp;quot;) + 2);&lt;br /&gt;print(collection.getObjectById(&amp;quot;test&amp;quot;));&lt;br /&gt;print(collection.getObjectById(&amp;quot;test2&amp;quot;));&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ce qui affiche 2 et 4.&lt;br /&gt;&lt;br /&gt;D&#39;ailleurs, je crois avoir compris pourquoi la doc est si mince sur V8: j&#39;ai obtenu le code sur leur SVN, et le numéro de version est 0.4.7. C&#39;est donc une beta. J&#39;ai passé leur code dans Doxygen, mais celui-ci est si peu documenté que ça ne donne pas grand chose.&lt;br /&gt;&lt;br /&gt;&lt;div style=&quot;border:1px solid #999999; padding:3px; font-weight:bold;&quot;&gt;EDIT: Vous pouvez maintenant télécharger la doc Doxygen de la v0.4.7 ici: &lt;a href=&quot;http://rapidshare.com/files/185473227/doxyV8.zip.html&quot;&gt;doxyV8.zip&lt;/a&gt;. Je sais, c&#39;est sur RapidShare, mais bon.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Prochaine étape: se débarrasser de cet horrible objet global.</description><link>http://deliriumcorp.blogspot.com/2009/01/v8-faire-paratre-un-objet-c-comme-un.html</link><author>noreply@blogger.com (Unknown)</author><thr:total>2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-8589498860624285456.post-3775420658568260392</guid><pubDate>Fri, 16 Jan 2009 23:02:00 +0000</pubDate><atom:updated>2009-01-17T20:30:03.060-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">blog</category><category domain="http://www.blogger.com/atom/ns#">c++</category><category domain="http://www.blogger.com/atom/ns#">v8</category><title>Ouverture du blog + V8: premières impressions</title><description>Je me lance donc dans l&#39;aventure bloggienne. On verra ce que ça va donner. Pour plus de détails, voir le message de droite.&lt;br /&gt;&lt;br /&gt;Mon stage me laissant beaucoup de temps libre, j&#39;ai dépoussiéré quelques vieux projets, dont un avec lequel j&#39;ai le goût d&#39;expérimenter des bindings C++ - JavaScript. &lt;a href=&quot;http://code.google.com/p/v8/&quot;&gt;V8&lt;/a&gt; étant sortit il n&#39;y a pas très longtemps, je me suis dit: pourquoi pas?&lt;br /&gt;&lt;br /&gt;Déjà, la compilation m&#39;a donné du fil à retordre. Il faut en effet utiliser &lt;a href=&quot;http://www.scons.org/&quot;&gt;Scons&lt;/a&gt;, outil avec lequel j&#39;étais très peu familier. Déjà, j&#39;ai eu besoin de quelques recherches Google pour y arriver. Puisque Scons refusait de fonctionner sous Mac OS X, j&#39;ai finalement lancé Parallels Desktop pour y aller sur Windows. Victoire! Ça fonctionne!&lt;br /&gt;&lt;br /&gt;J&#39;obtint alors un gros .lib de près de 70 Mo, que je m&#39;empressait d&#39;inclure à un nouveau projet VC++. Réalisant à quel point cette lib était grosse, je me suis dit qu&#39;il devait bien y avoir une meilleure façon de procéder. Je suis donc retourné dans la doc et j&#39;ai appris qu&#39;on pouvait décider d&#39;obtenir une DLL à la place en entrant un certain paramètre. Tadam! J&#39;ai maintenant une jolie DLL (compilée en release, naturellement) et un petit .lib de 150 Ko. Bon, la compilation de mon projet me donne 10 warnings qui me disent tous que telle ou telle méthode doit avoir une interface de DLL pour les clients d&#39;une certaine classe (warning C4251, pour être plus précis). Si quelqu&#39;un sait de quoi il s&#39;agit, qu&#39;il me le dise. Parce que moi et les DLL, c&#39;est un peu nébuleux.&lt;br /&gt;&lt;br /&gt;Mais avant tout, il me fallait évidemment du code pour voir si la configuration de mon IDE était bonne. Alors, naturellement, je suis allé sur le site officiel de V8 (aka quelques pages sur Google Code) et j&#39;ai ramassé le &lt;a href=&quot;http://code.google.com/intl/fr/apis/v8/get_started.html&quot;&gt;&quot;Hello World&quot;&lt;/a&gt;. C&#39;était assez simple à comprendre. Je dois dire qu&#39;à vu de nez, comme ça, ça m&#39;a l&#39;air assez propre, comme code.&lt;br /&gt;&lt;br /&gt;Résultat des courses: un joli programme qui affiche &quot;Hello World!&quot;&lt;br /&gt;&lt;br /&gt;Prochaine étape: faire apparaître un objet C++ comme un objet JS. Ça devrait être assez complexe, vu que la documentation de V8 se résume à un hello world, un &quot;embedding guide&quot; qui ne fait que survoler les fonctionnalités de la bibliothèque, ainsi que deux exemples. Et Google donne peu de résultats sur le sujet. Je risque fort probablement de me baser sur ces exemples pour mes essais.&lt;br /&gt;&lt;br /&gt;Donc, si vous voulez vous aussi binder C++ et JavaScript, eh bien, comme disent les Anglophones: Stay tuned!</description><link>http://deliriumcorp.blogspot.com/2009/01/ouverture-du-blog-v8-premires.html</link><author>noreply@blogger.com (Unknown)</author><thr:total>3</thr:total></item></channel></rss>