Entries for tag c++

Thu Dec 24 2009

Blog, Vrac

blog, c++, linode, linux, mongodb, nginx, v8

0 comment

Bilan du blog pour 2009

2009 s'achève. Encore une année passée à fond la caisse. Rien vu passé en fait. Fin d'année rime avec bilan et bêtisier (et prévisions astrologiques, mais on n'en a rien à foutre). Ok. RAS pour l'intro.

Au mois de février, ou un truc du genre, je m'étais juré d'ouvrir un blog. Je m'étais dit la même chose l'année précédente et l'année d'avant aussi. Bref, y a quelque chose qui a sérieusement merdé en 2009 pour que ce blog puisse enfin voir le jour.

Ce qui a déconné grave en 2009

Tout a commencé avec l'envie inexpliquée de me choper un VPS. Après investigations, mon choix s'est porté sur Linode. A postériori, ce choix n'était pas mauvais puisque leurs plateformes Xen déchirent leur race. Bon, j'aurais pu faire l'erreur de me trouver piéger quant aux choix de l'OS, du kernel et tout, mais non, il a fallu que Slackware soit dispo. Franchement là je commençais à me dire "putain avec ces conneries tu vas finir par l'ouvrir ton blog". Je vous raconte pas les boules.

En parallèle, la nécessité de plus en plus pressante de changer de laptop se faisait.. de plus en plus pressante. En gros, je lorgnais sur des ASUS de gamers, de quoi assouvir mes envies de meurtres et pouvoir y foutre sereinement une distrib linux en dual boot. Pourquoi ASUS, pourquoi un PC d'ailleurs ? C'est une excellente question, mais j'ai autre chose à foutre faire que d'y répondre (j'ai déjà mis foutre deux phrases plus haut). Non, vraiment, la seule chose dont j'étais sur, c'est que MOI vivant, JAMAIS je ne claquerais 1500 euros dans une arnaque de MacBook. Encore une heure avant de me rendre sur l'App Store un soir et y claquer frénétiquement juste à peine moins de 1500 euros tel un maniaco compulso-dépressif, j'aurais maintenu mes positions sous la tortures. Heureusement que je suis blindé de thunes.

Essayons de bien comprendre: à ce moment là de l'année, rien ne se passait comme prévu. Putain j'allais quand même pas finir par installer Wordpress ou Dotclear. Si près du but, sans la moindre embuche, c'est pas possible ou quoi. Y a pas moyen.

Une solution de secours: virer LAMP

Et remplacer cette stack par LEMC++. Une solution de secours à la RACHE, nous sommes d'accord. Au moins avec un peu de chance ça devrait pouvoir ruiner ce qu'il restait de 2009, d'autant plus que je m'étais dis "hum hum, tu vas te remettre à la guitare".

Pas le temps de placer 3 accords de 7ième mineur, que déjà mon VPS compile GCC trunk plus rapidement que le Mac. Et les gars de Linode ne bronchent pas. Il ne s'agit pourtant que d'un plan 360. Moi je vous dis, ça pue... d'autant plus que les concours de circonstances fortuites et malheureuses s'enchainent:

Consternant. Et ce n'est pas un ApacheBench qui viendra contrecarrer cet état de fait. Oui, c'est affligeant, mais cette daube encaisse plus de 5000 requêtes par seconde.

Server Software:        nginx/0.8.27
Server Hostname:        blog.runpac.com
Server Port:            80

Document Path:          /
Document Length:        21134 bytes

Concurrency Level:      10
Time taken for tests:   0.173 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      21271000 bytes
HTML transferred:       21134000 bytes
Requests per second:    5779.68 [#/sec] (mean)
Time per request:       1.730 [ms] (mean)
Time per request:       0.173 [ms] (mean, across all concurrent requests)
Transfer rate:          120058.15 [Kbytes/sec] received

Sur du 360...

$ free -m
             total       used       free     shared    buffers     cached
Mem:           348         77        271          0         17         42
-/+ buffers/cache:         17        330
Swap:          255          0        255

Mais qu'est-ce qui a bien pu déconner ??

Sauvé par les stats de visites

Manquerait plus que le site soit fréquenté! Après un mois et demi d'existence, seul une poignée d'inconscients (autres que les déferlantes de bots google et baidu) atterrissent ici. Franchement, au début j'ai eu peur. Déjà que je me fais chier à blogger en français EXPRES. Par chance vous n'êtes pas plus de 20 peulés chaque jour à perdre votre temps ici.

Faite gaffe quand même. 2009 n'est pas fini.

Sun Nov 29 2009

Programming

boost, c++, json, variant

1 comment

Simple modélisation de JSON en C++

Il existe un certain nombre de parsers et autres librairies en C++ pour traiter du JSON (voir en bas de la page). Il manquerait Boost.PropertyTree qui a récemment été intégré dans boost.

En ce qui me concerne, je n'ai que très rarement besoins de manipuler du JSON de fond en comble, c'est à dire, par exemple, parser une chaine en JSON ou écrire dans un fichier avec ce format. Ce qui m'est utile en revanche, est de balancer des valeurs JSON-esques dans un container qui servira ensuite d'input à d'autres composants. C'est vague, je sais, c'est fait pour.

Le container en question est donc sommé d'accepter des strings, tableaux, objets, booléens etc. Bref, tout ce qui fait l'intérêt de JSON. Une des techniques que j'utilise est basée sur Boost.Variant. L'intérêt de Boost.Variant par rapport à Boost.Any est qu'il est type safe. Un mécanisme de visiteur permet de manipuler précisément les types wrappés, ce qui est utile lorsque le container en question n'est qu'un container de "passage" entre composants. L'autre intérêt de variant est sa propension à être récursif, tout comme JSON. Ca tombe bien.

Dans le code qui suit, json_type est le type généric qui modélise une valeur JSON. json_array, json_object sont des json_type. En plus, on accepte des std::string, bool etc. Ce n'est pas une implémentation de JSON fidèle au bit près. Comme je le disais, je veux juste du JSON-esque:

typedef boost::make_recursive_variant
<
    int
  , double
  , bool
  , std::string
  , std::unordered_map<std::string, boost::recursive_variant_> // object
  , std::vector<boost::recursive_variant_> // array

>::type json_type; // notre type generic

typedef std::unordered_map<std::string, json_type> json_object;

typedef std::vector<json_type> json_array;

On notera l'utilisation de std::unordered_map. Un boost::unordered_map ferait tout autant l'affaire. boost::make_recursive_variant permet de rendre le variant récursif. Il accepte dès lors sans broncher un std::vector<boost::recursive_variant_>. Vous aurez compris qu'il s'agit de la modélisation du array JSON. Un typedef qui va bien permet de déclarer json_array à partir de std::vector<json_type>. La boucle est bouclée.

A l'utilisation, ça donne ce genre de chose:

json_array arr {3.14, 21, true}; //initializer list goodies (C++0x)
  
json_object obj;
obj["key"] = 42;
obj["str"] = std::string("hello");
obj["arr"] = arr;

Ok, mais faire ça ne sert à rien. Effectivement. Rappelez-vous, il s'agit d'un container de passage. Un autre composant va devoir se démerder (encore une fois, sans broncher) pour faire quelque chose d'utile avec. C'est là que boost::static_visitor entre en jeu. On va pouvoir traiter finement les types wrappés (std::string, int, std::vector...). Le principe est le suivant:

// un type T quelconque (pseudo code)
struct json_visitor : public boost::static_visitor<T>
{
    T operator()(const json_object& val) const
    {
        //...
    }

    T operator()(const json_array& val) const
    {
        //...
    }

    T operator()(const std::string& val) const
    {
        //...
    }
    
    // ...
};

// on applique le visitor à notre json_type
boost::apply_visitor(json_visitor(), json_type);

Par exemple, faire un output au format JSON de notre json_type. On va déclarer un visitor dérivant de boost::static_visitor<std::string> qui se chargera de formater le tout:

struct json_conv_visitor : public boost::static_visitor<std::string>
{
    std::string operator()(const json_object& val) const
    {
        std::ostringstream os;
        os << "{";
        for (json_object::const_iterator i(val.begin()), e(val.end())
            ; i != e; ++i)
        {
            os << i->first << ": "
               << boost::apply_visitor(json_conv_visitor(), i->second)
               << ", ";
        }
        os << "}";
        return os.str();
    }

    std::string operator()(const json_array& val) const
    {
        std::ostringstream os;
        os << "[";
        for (json_array::const_iterator i(val.begin()), e(val.end())
            ; i != e; ++i)
        {
            os << boost::apply_visitor(json_conv_visitor(), *i) 
               << ", ";
        }
        os << "]";
        return os.str();
    }

    std::string operator()(const std::string& val) const
    {
        return std::string("\"").append(val).append("\"");
    }
    
    template<typename T> // le reste est refilé à boost::lexical_cast
    std::string operator()(const T& val) const
    {
        return boost::lexical_cast<std::string>(val);
    }
};

Appliqué à l'exemple plus haut, ça retourne:

{str: "hello", key: 42, arr: [3.1400000000000001, 21, 1, ], }

Voila, le code complet est dispo sur github ici. Si ça vous intéresse, servez-vous. Un de ces 4, on parlera d'une manière de parser une chaine JSON pour filler ce genre de variant, sans utiliser Spirit. Sur ce, a+

« newer