<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://www.maybeuninit.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.maybeuninit.com/" rel="alternate" type="text/html" /><updated>2026-05-06T06:58:52+00:00</updated><id>https://www.maybeuninit.com/feed.xml</id><title type="html">maybe uninit</title><subtitle>Adrien Zinger - Blog</subtitle><author><name>Adrien Zinger</name></author><entry><title type="html">Conception par Contrat, Juste un rapide coup d’œil</title><link href="https://www.maybeuninit.com/2026/03/05/conception-par-contrat.html" rel="alternate" type="text/html" title="Conception par Contrat, Juste un rapide coup d’œil" /><published>2026-03-05T00:00:00+00:00</published><updated>2026-03-05T00:00:00+00:00</updated><id>https://www.maybeuninit.com/2026/03/05/conception-par-contrat</id><content type="html" xml:base="https://www.maybeuninit.com/2026/03/05/conception-par-contrat.html"><![CDATA[<h1 class="web">Conception par Contrat, Juste un rapide coup d'œil</h1>

<div class="print">
    <h1 style="text-align: center;">Conception par Contrat, Juste un rapide coup d'œil</h1>
    <div style="text-align: center;">Adrien Zinger, mars 2026, maybeuninit.com</div>
</div>

<h1 id="conception-par-contrat">Conception par Contrat</h1>

<p>Dans cet article, je décortique un relativement vieux papier de Robby FINDLER
et de M FELLEISEN.</p>

<p>Article libre, sauf si j’oublie, je mettrai un lien à la fin. Je dis
relativement vieux, parce qu’en fait, il date juste de 2002. Simplement, dans
ses exemples, il se réfère à DrScheme qui a depuis un moment passé le relais, il me semble.</p>

<p>Donc on va voir ici avec Racket, un nouveau DrScheme, ce que ça donne les
contrats dans un langage, c’est quoi, à quoi ça sert et surtout : qu’est-ce que
ça veut résoudre comme problème.</p>

<h2 id="définition-dun-contrat">Définition d’un contrat</h2>

<p>Un contrat s’applique à une fonction et défini ce qui doit
être respecté par l’appelant et par la fonction. Les paramêtres
et la valeur de retour sont contraint de respecter les rêgles
du contrat.</p>

<p>Ci-dessous la première phrase de Wikipédia:</p>

<p><em>“La programmation par contrat (en anglais, design by contract ou DBC) est un</em>
<em>paradigme de programmation dans lequel le déroulement des traitements est</em>
<em>régi par des règles.”</em></p>

<p>Utiliser abondamment les contrats est donc un paradigme comme l’orienté objet,
le fonctionnel, etc. À noter que ce paradigme comme beaucoup d’autre est
compatible avec l’usage d’autre paradigme.</p>

<p>En C++, par exemple, faire de la programmation fonctionnelle n’empêche pas
de faire de la programmation orienté objet à côté. Au même titre qu’il
n’empêchera pas à l’avenir de faire de la programmation par contrat (C++26).</p>

<p>Le language, ou votre fçon de coder vous assure que les règles suivante sont
respéctées :</p>

<ul>
  <li>Précondition (les paramètres)</li>
  <li>Postcontition (le truc à droite de <code class="language-plaintext highlighter-rouge">return</code>)</li>
  <li>Les invariants (ce qui est toujours vrai)</li>
  <li>Les variants (ce qui… change)</li>
</ul>

<h2 id="en-pratique">En pratique</h2>

<p>En pratique, un contrat fait que votre programme ne compile pas s’il vérifie
qu’une règle n’est pas respecté. Et s’il ne peut pas vérifier pendant la
compilation, au pire des cas, il fait “paniquer” le programme en donnant une
raison (la plus précise possible).</p>

<p>Alors voilà, c’est le moment où j’écris du Racket…</p>

<pre><code class="language-rkt">(define/contract (add-positive x y)
  (-&gt; positive? positive? positive?)
  (+ x y))
</code></pre>

<p>La fonction <code class="language-plaintext highlighter-rouge">add-positive</code> permet à son appelant d’ajouter deux nombres positifs
entre eux. Les grandes lois des mathématiques nous assurent que le résultat
sera positif, mais pour notre exemple, on va dire que le contrat vérifie lui
aussi que la valeur de retour est bien positive.</p>

<p><code class="language-plaintext highlighter-rouge">define/contract</code> ici est le mot clef pour commencer une fonction avec un
contrat. Le contrat <code class="language-plaintext highlighter-rouge">-&gt; positive? positive? positive?</code> s’applique sur la
fonction avec deux parametrès (x et y). Comme c’est un langage définissant les
opérations sur une pile, ça peut se lire ainsi :</p>

<p><em>“On doit avoir x positif et y positif, on obtiendra alors un positif”</em></p>

<p>Cet exemple est un peu simpliste, le but est de voir un peu ce que ça
implique. Par exemple, imaginons que je ne respecte pas le contrat d’emblée.</p>

<pre><code class="language-rkt">(define result (add-positive -3 4))
</code></pre>

<p>Je m’attends à une erreur, un peu comme une erreur de type en fait. Et
effectivement :</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>add-positive: contract violation
  expected: positive?
  given: -3
  in: the 1st argument of
      (-&gt; positive? positive? positive?)
  contract from: (function add-positive)
</code></pre></div></div>

<p>On peut également s’attendre à ce qu’une erreur similaire survienne pour la
valeur de retour. Dans l’exemple précédent, <code class="language-plaintext highlighter-rouge">positive?</code> est une fonction
pre-définie. Mais nous sommes libres d’en créer de nouvelles :</p>

<pre><code class="language-rkt">;; math-utils.rkt
(define my-range? (lambda (x) (and (&gt;= x 4) (&lt;= x 8))))                                          
(define/contract (add-positive-return-my-range x y)                                              
  (-&gt; positive? positive? my-range?)                                                             
  (+ x y)) 


;; main.rkt
(define result (add-positive-return-my-range 9 4))
</code></pre>

<p>Dans cet exemple, je déninis une fourchette de valeurs imaginaires (entre 4
et 8) et je définis une fonction <code class="language-plaintext highlighter-rouge">add-positive</code> qui vérifie que la valeur de
retour est bien dans cette fourchette.</p>

<p>Petit disclaimer: les erreurs que je montre ici sont relevées au <em>runtime</em>. En
tout cas en ce qui concerne racket. Donc, même si c’est intéressant, ça
n’empêche pas <em>vraiment</em> d’écrire du code bugué (à mon sens).</p>

<p>Ces deux petits exemples d’introdution nous permettent de définir plus
clairement deux concepts aux noms un peu bizarre : le <em>domain</em> et le <em>range</em>. Le
domain est en fait ce qui concerne les paramètres, tandis que le range ce
qui concerne la valeur de retour.</p>

<p>Dans la langue de Molière, domain donne <em>“dommaine de définition”</em> ou encore
<em>“ensemble de départ”</em> et range donne <em>“ensemble d’arrivée”</em>.</p>

<h2 id="ce-qui-y-ressemble">Ce qui y ressemble</h2>

<p>En soit, ce code en Racket pourrait correspondre à une fonction plus commune.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">add_positive_return_my_range</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">i32</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="nb">i32</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Result</span><span class="o">&lt;</span><span class="nb">i32</span><span class="o">&gt;</span> <span class="p">{</span>
  <span class="nf">check_domain</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
  <span class="k">let</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">x</span> <span class="o">+</span> <span class="n">y</span><span class="p">;</span>
  <span class="nf">check_range</span><span class="p">(</span><span class="n">ret</span><span class="p">)</span><span class="o">?</span><span class="p">;</span>
  <span class="n">ret</span>
<span class="p">}</span>
</code></pre></div></div>

<p>On se rend tout de suite compte qu’avec un meilleur typage, on résoudrai
déjà une bonne partie des problèmes rien qu’à la compilation. En
remplaçant <code class="language-plaintext highlighter-rouge">x: i32, y: i32</code> par <code class="language-plaintext highlighter-rouge">x: u32, y: u32</code>, <code class="language-plaintext highlighter-rouge">check_domain</code> deviendrait
redondant. En fait, dans un programme correct (qui ne viole aucun contrat),
chacun de ces tests est redondant et pourrait être retiré sans affecter le
programme final.</p>

<p>D’après mon expérience, on peut programmer
avec un style “orienté par contrat” dans n’importe quel langage. Si c’est
plutôt difficile de s’y tenir avec un langage dynamiquement typé, c’est bien
plus simple avec un statiquement typé, ou graduellement.</p>

<p>Dans un langage graduellement typé comme Python, on trouve un certain type
d’assertion qui ressemble aux contrats. Lorsqu’on essaie d’ajouter une
chaine de caractère à un nombre par exemple. On retrouve ici une assertion
automatique de la VM python… La feature reste très
légère comparée aux capacités des contrats.</p>

<p>En C++ on retrouve une autre feature, les concepts. Même s’ils ne font pas
du tout la même chose, ça me donne l’idée qu’on peut jouer avec de la même
manière, en profitant du static dispatch. On ne peut pas vraiment vérifier
de logique metiers cependant. Mais avec un bon système de type, encore une
fois, on s’en sort…</p>

<pre><code class="language-C++">template&lt;typename T&gt;
concept Addable = requires(T a, T b) {
    a + b;
};
</code></pre>

<p>En soit, on ne peut pas tester les invariants dans ces
langages autrement qu’en ajoutant un <code class="language-plaintext highlighter-rouge">assert(x &gt;= 0 &amp;&amp; y &gt;= 0)</code>. En C++
comme en Rust, les features les plus avancés dans ce domaine se limite
aux types. Ce qui est déjà PAS MAL.</p>

<p>Un certain nombre d’outils se basant sur le typage permettent de dénicher
des erreurs de logique métier qu’on pourrait éviter (ou gérer) avec
des contrats. Je pense à l’analyse statique et à l’interprétation abstraite.
Cette dernière était mon idée principale de la résolution de type dans
eniem (mon langage nul).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>let not0 = (x) { x != 0 }
let a = 15 as not0
</code></pre></div></div>

<h2 id="la-gestion-des-erreurs">La gestion des erreurs</h2>

<p>Lorsqu’un contrat est rompu, il faut bien blâmer quelqu’un. Dans une fonction
de premier ordre, et bien c’est facile. La faute revient clairement à
l’appelant si l’erreur est dans l’ensemble de départ. C’est moins clair
lorsque l’erreur est dans l’ensemble d’arrivée, mais généralement c’est la
faute de la fonction.</p>

<p>Dans un exemple précédent, le retour de la fonction
<code class="language-plaintext highlighter-rouge">add-positive-return-my-range</code> casse le contrat à cause de l’ensemble d’arrivée.
Cependant, c’est aussi la faute d’un manque de précision dans le contrat.</p>

<p>Dans l’exemple précédent, l’erreur fournie est la suivante :</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>add-positive-return-my-range: broke its own contract
  promised: my-range?
  produced: 13
  in: the range of
      (-&gt; positive? positive? my-range?)
  contract from: 
      (function add-positive-return-my-range)
  blaming: (function add-positive-return-my-range)
   (assuming the contract is correct)
</code></pre></div></div>

<p>Racket blâme la fonction elle-même pour avoir rompu son propre contrat. Une
version plus correcte de cette fonction serait :</p>

<pre><code class="language-rkt">(define/contract (better-add x y)

  (-&gt;i ([x positive?] [y positive?])
    #:pre (x y) (my-range? (+ x y))
    any)

  (+ x y))
</code></pre>

<p>Le résultat n’est pas tout à fait juste pour moi, car on continue de blâmer
la fonction elle-même. Néanmoins, on a un indice sur le fait que l’erreur
vient du domaine de définition. Donc de l’appelant.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>better-add: contract violation
  #:pre condition violation; variables are:
      x: 9
      y: 4
  in: (-&gt;i
       ((x positive?) (y positive?))
       #:pre
       (x y)
       (my-range? (+ x y))
       any)
  contract from: (function better-add)
</code></pre></div></div>

<p>La question de savoir qui a eu tort lorsque le programme relève une erreur
peut m’aider à debuguer. Mais j’imagine un tas d’autre application métier, je
pense que c’est plutôt évident.</p>

<p>Avec des fonctions de plus haut degré, c’est plus compliqué.</p>

<h2 id="error-handling-dans-les-fonctions-de-haut-degré">Error handling dans les fonctions de haut degré</h2>

<p>Prenons un exemple commun.</p>

<p>Je vais m’éloigner un peu du sujet, mais je trouve que l’exemple qui va suivre
illustre plutôt bien le problème.</p>

<p>Voici un morceau de java:</p>

<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="nc">Stream</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="nf">some_mapping</span><span class="o">(</span><span class="nc">Stream</span><span class="o">&lt;</span><span class="nc">Integer</span><span class="o">&gt;</span> <span class="n">stream</span><span class="o">)</span> <span class="o">{</span>
	<span class="k">return</span> <span class="n">stream</span><span class="o">.</span><span class="na">map</span><span class="o">(</span><span class="n">i</span> <span class="o">-&gt;</span> <span class="n">self</span><span class="o">.</span><span class="na">throwable_at_runtime</span><span class="o">(</span><span class="n">i</span><span class="o">))</span>
<span class="o">}</span>
</code></pre></div></div>

<p>Disons que dans un programme, on trouve une fonction qui peut relever une
exception. Mais l’exception peut arriver bien plus tard. Par exemple quand
<code class="language-plaintext highlighter-rouge">stream.collect(...)</code> est appelé. Comme je l’ai dit, savoir d’où vient
l’erreur aide à débuguer et ne peut avoir que des repercutions positives sur le
programme et son usage. Ici, quand l’erreur est relevée, on peine à connaitre le
responsable :</p>

<p>a. <code class="language-plaintext highlighter-rouge">some_mapping</code>
b. l’appelant de <code class="language-plaintext highlighter-rouge">some_mapping</code>
c. <code class="language-plaintext highlighter-rouge">throwable_at_runtime</code>
d. l’appelant de <code class="language-plaintext highlighter-rouge">collect</code></p>

<p>Je rappelle que dans une situation réelle, <code class="language-plaintext highlighter-rouge">throwable_at_runtime</code> a un nom
beaucoup moins explicite. Par exemple <code class="language-plaintext highlighter-rouge">match</code> dans Matcher, <code class="language-plaintext highlighter-rouge">Integer.parseInt</code>,
<code class="language-plaintext highlighter-rouge">get</code> et <code class="language-plaintext highlighter-rouge">add</code> dans de nombreux contexts.</p>

<hr />

<pre><code class="language-rkt">(define saved (lambda (x) 50))
(define/contract (save f)
  (-&gt; (-&gt; bigger-than-zero? bigger-than-zero?) any)
  (set! saved f))

(define (use n)
  (-&gt; bigger-than-zero? bigger-than-zero?)
  (saved n))

(save (lambda (x) (x)))
(displayln (format "Result: ~a" (use 5)))
</code></pre>

<p>Dans cet exemple, je définis <code class="language-plaintext highlighter-rouge">saved</code> avec une lambda qui n’a pas vraiment
d’importance. Puis je donne une fonction <code class="language-plaintext highlighter-rouge">save</code> qui prend en argument une
lambda qui doit respecter le contrat : <em>“prend un argument superieur à zéro
et retourne une valeur supérieur à zéro”</em>.</p>

<p>Ici, c’est impossible de savoir <code class="language-plaintext highlighter-rouge">saved</code> sera toujours appliqué à des nombres
positifs. Encore pire, on ne peut pas prédire que <code class="language-plaintext highlighter-rouge">saved</code> retournera bien
une valeur positive !</p>

<p>Le parallèle avec l’exemple java. Une <code class="language-plaintext highlighter-rouge">RuntimeException</code> incarne parfaitement
cette situation. C’est-à-dire que la fonction peut “fail”, car on est dans
l’incapacité de prédire avec quel argument elle va être appelée. Ou bien,
on ne peut garantir que le type retourné est correct. Ou les deux.</p>

<p><code class="language-plaintext highlighter-rouge">usePattern</code> relève une exception au runtime si le paramètre est null,
ou n’est pas une regex.</p>

<p>Quand on y réfléchit bien, <code class="language-plaintext highlighter-rouge">java.lang.IllegalArgumentException</code> étend
<code class="language-plaintext highlighter-rouge">RuntimeException</code>. Et justement, <code class="language-plaintext highlighter-rouge">gradle build</code> ne donne aucune alerte
quand il ne voit pas de <code class="language-plaintext highlighter-rouge">try/catch</code> autour d’une telle exception. C’est
le seul type d’exception qu’il veut bien voir dans des fonctions
de plus haut degré.</p>

<p>Il ne donne pas d’erreur avant d’effectivement appliquer effectivement
la méthode <code class="language-plaintext highlighter-rouge">usePattern</code>, comme Racket ne donne son erreur qu’à l’appel.</p>

<p>Si j’appelle <code class="language-plaintext highlighter-rouge">use</code> avec un mauvais argument, par exemple <code class="language-plaintext highlighter-rouge">-5</code></p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>save: broke its own contract
  promised: bigger-than-zero?
  produced: -5
  in: the 1st argument of
      the 1st argument of
      (-&gt;
       (-&gt; bigger-than-zero? bigger-than-zero?)
       any)
  contract from: (function save)
  blaming: (function save)
   (assuming the contract is correct)
  at: ./src/delayed.rkt:9:18
  context...:
   &lt;...&gt;/blame.rkt:350:0: raise-blame-error
   &lt;...&gt;/arrow-higher-order.rkt:375:33
   ./main.rkt:19:0
   body of ./main.rkt
</code></pre></div></div>

<p>On dirait qu’on blâme save ici, non ? Qu’est-ce que vous en comprenez ?</p>

<p>Si maintenant j’appelle avec <code class="language-plaintext highlighter-rouge">5</code>, mais avant je set <code class="language-plaintext highlighter-rouge">saved</code> avec une lambda
qui revoit l’inverse :</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>save: contract violation
  expected: bigger-than-zero?
  given: -5
  in: the range of
      the 1st argument of
      (-&gt;
       (-&gt; bigger-than-zero? bigger-than-zero?)
       any)
  contract from: (function save)
  blaming: ./src/delayed.rkt
   (assuming the contract is correct)
  at: ./src/delayed.rkt:9:18
  context...:
   &lt;...&gt;/blame.rkt:350:0: raise-blame-error
   &lt;...&gt;/arrow-higher-order.rkt:379:33
   ./main.rkt:19:0
   body of "./main.rkt"
</code></pre></div></div>

<p>Le moins qu’on puisse dire, c’est qu’on n’y comprend rien. Dans le deuxième cas,
effectivement, je m’attends à blâmer delayed (là où j’ai la définition de
<code class="language-plaintext highlighter-rouge">saved</code>).</p>

<p>Mais dans le premier cas, je m’attendais à ce qu’on blâme l’appel de <code class="language-plaintext highlighter-rouge">use</code>. Ou
bien que ça soit plus explicite (si c’est le cas).</p>

<hr />

<p>Pour revenir sur l’exemple en java, après, j’en aurai terminé. Voilà l’erreur que j’ai :</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Exception in thread "main" java.lang.RuntimeException
        at org.example.App.throwable_at_runtime(App.java:12)
        at org.example.App.lambda$some_mapping$0(App.java:16)
        at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
        at java.base/java.util.Vector$VectorSpliterator.forEachRemaining(Vector.java:1464)
        at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
        at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
        at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
        at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
        at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
        at org.example.App.main(App.java:24)
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">throwable_at_runtime</code> est toujours la cause du problème. Peu importe la
raison. Donc le développeur doit spécifier si c’est un problème d’argument, un
problème extérieur ou qu’importe. De plus, le principe de la stack trace nous
empêche de raisonner avec la largesse qu’on souhaiterait. Par exemple un appel
à <code class="language-plaintext highlighter-rouge">saved</code> avec une lambda invalide serait invisible dans l’erreur. Il faudrai
développer tout le programme autour du mécanisme, ce qui n’est pas toujours
possible.</p>

<h2 id="conclusion">Conclusion</h2>

<p>Je vous laisse en conclure ce que vous voulez.</p>

<p>Ah oui, le lien : <a href="https://users.cs.northwestern.edu/~robby/pubs/papers/ho-contracts-techreport.pdf">ho contracts techreport</a>.</p>]]></content><author><name>Adrien Zinger</name></author><summary type="html"><![CDATA[Dans cet article, je décortique un papier qui parle de la conception par contrat. Un paradigme qui vaut le coup de connaitre.]]></summary></entry><entry><title type="html">Fiche mémo: parsing, if pattern</title><link href="https://www.maybeuninit.com/2023/02/24/memo-parsing.html" rel="alternate" type="text/html" title="Fiche mémo: parsing, if pattern" /><published>2023-02-24T00:00:00+00:00</published><updated>2023-02-24T00:00:00+00:00</updated><id>https://www.maybeuninit.com/2023/02/24/memo-parsing</id><content type="html" xml:base="https://www.maybeuninit.com/2023/02/24/memo-parsing.html"><![CDATA[<h1 class="web">Fiche mémo: parsing, <em>if pattern</em></h1>

<p><span class="web" style="color: #A0A0A0">[2023-02-24] #Parsing #State_machine #Code
</span></p>

<div class="print">
    <h1 style="text-align: center;">Fiche mémo: parsing, <em>if pattern</em></h1>
    <div style="text-align: center;">Adrien Zinger, février 2023, maybeuninit.com</div>
</div>

<p>Lors de la conception d’une grammaire, la présence de certaines structures syntaxiques peut entraîner des ambiguïtés. Une grammaire ayant plusieurs arbres de dérivation possibles pour une même phrase est une grammaire dite <em>“ambiguë”</em>, ce qui peut compliquer l’analyse et la compréhension du langage en question. Prenons l’exemple du pattern <em>if</em>, qui branche vers un état ou un autre selon le résultat d’une expression.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">stmt</span> <span class="p">:</span> <span class="nx">IF</span> <span class="nx">EXPR</span> <span class="nx">then</span> <span class="nx">stmt</span>
     <span class="o">|</span> <span class="nx">IF</span> <span class="nx">EXPR</span> <span class="nx">then</span> <span class="nx">stmt</span> <span class="nx">IF</span> <span class="nx">stmt</span>
     <span class="o">|</span> <span class="nx">STMT</span> <span class="p">;</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">if E1 then if E2 then S1 else S2</code></p>

<p>On ne peut pas déterminer avec la grammaire ci-dessus si la phrase sera traduite en un arbre tel que <code class="language-plaintext highlighter-rouge">(if E1 then (if E2 then S1) else S2)</code> ou <code class="language-plaintext highlighter-rouge">(if E1 then (if E2 then S1 else S2))</code>. Deux arbres de dérivation pour la même phrase. Afin de résoudre l’ambiguïté causée par la présence d’un pattern tel que celui-ci, nous pouvons remplacer la partie grammaticale par une structure syntaxique équivalente, mais qui ne pose pas de difficulté pour l’analyse syntaxique.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">stmt</span> <span class="p">:</span>      <span class="nx">matched</span> <span class="o">|</span> <span class="nx">unmatched</span> <span class="p">;</span>
<span class="nl">matched</span> <span class="p">:</span>   <span class="nx">IF</span> <span class="nx">EXPR</span> <span class="nx">then</span> <span class="nx">matched</span> <span class="nx">ELSE</span> <span class="nx">matched</span> <span class="o">|</span> <span class="nx">STMT</span> <span class="p">;</span>
<span class="nl">unmatched</span> <span class="p">:</span> <span class="nx">IF</span> <span class="nx">EXPR</span> <span class="nx">then</span> <span class="nx">matched</span>
          <span class="o">|</span> <span class="nx">IF</span> <span class="nx">EXPR</span> <span class="nx">then</span> <span class="nx">matched</span> <span class="nx">ELSE</span> <span class="nx">unmatched</span> <span class="p">;</span>
</code></pre></div></div>

<p>La factorisation à gauche représente toujours un défi lorsqu’on conçoit un générateur de parseurs pour une grammaire. Dans le cas présent, cette difficulté est exacerbée par la possibilité que le token IF puisse être le premier symbole de plusieurs états générés, du fait, des conflits peuvent survenir entre les règles de production <em>unmatched</em> et <em>matched</em>. Si l’on décide de raisonner dès la lecture du <em>IF</em>, ces conflits peuvent apparaître, compromettant ainsi l’efficacité et la fiabilité de la grammaire. Dans de tels cas, un générateur de parseurs pourrait prendre une décision arbitraire pour résoudre le conflit, entraînant ainsi une possible altération de la grammaire désirée.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">matched</span> <span class="p">:</span>   <span class="nx">IF</span> <span class="cm">/* { printf("pop\n"); } */</span> <span class="nx">EXPR</span> <span class="nx">THEN</span> <span class="nx">matched</span> <span class="nx">ELSE</span> <span class="nx">matched</span>
          <span class="o">|</span> <span class="nx">STMT</span> <span class="p">;</span>
<span class="nl">unmatched</span> <span class="p">:</span> <span class="nx">IF</span> <span class="cm">/* { printf("pop\n"); } */</span> <span class="nx">EXPR</span> <span class="nx">THEN</span> <span class="nx">matched</span>
          <span class="o">|</span> <span class="nx">IF</span> <span class="cm">/* { printf("pop\n"); } */</span> <span class="nx">EXPR</span> <span class="nx">THEN</span> <span class="nx">matched</span> <span class="nx">ELSE</span> <span class="nx">unmatched</span> <span class="p">;</span>
</code></pre></div></div>

<p>Le pattern en question pose un problème majeur en ce sens qu’il nécessite la lecture complète du code pour pouvoir réduire le statement à sa racine, ce qui peut représenter un problème important lorsqu’on souhaite compiler le code en une seule passe. Pour pallier cette difficulté, certains langages optent pour des patterns plus contraignants. Par exemple, en Rust, les statements doivent obligatoirement être entourés d’accolades. En Nix, toute condition doit retourner une valeur car la résolution de type requiert la spécification de chaque alternative, ce qui permet de supprimer la règle de production <em>unmatched</em>.</p>

<div class="language-nix highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">x</span><span class="p">:</span> <span class="nv">T</span> <span class="o">=</span> <span class="k">if</span> <span class="o">...</span> <span class="k">then</span> <span class="nv">T</span> <span class="k">else</span> <span class="nv">T</span>
</code></pre></div></div>

<p>En obligeant l’utilisateur à définir toutes les alternatives, il est possible d’inférer le type de l’expression <em>if</em>, entre autres. Cette inférence est généralement effectuée lors du preprocessing si le langage utilisé est compilé. Toutefois, certains outils de développement peuvent proposer de réaliser cette vérification pendant l’écriture du code.</p>

<p>Pour finir, analysons l’expression suivante avec un <em>parser combinator</em>. Cette méthode, ne construisant pas de machine à état à proprement dit, devra résoudre les conflits à l’exécution. Pour ce faire, il convient d’adapter préalablement la grammaire pour qu’elle corresponde autant que possible à un parseur de ce type.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">stmt</span> <span class="p">:</span>              <span class="nx">matched_eof</span> <span class="o">|</span> <span class="nx">unmatched_eof</span> <span class="p">;</span>

<span class="nl">matched_eof</span> <span class="p">:</span>       <span class="nx">matched</span> <span class="nx">EOF</span> <span class="p">;</span>
<span class="nl">unmatched_eof</span> <span class="p">:</span>     <span class="nx">unmatched</span> <span class="nx">EOF</span> <span class="p">;</span>

<span class="nl">matched</span> <span class="p">:</span>           <span class="nx">token_if</span> <span class="nx">EXPR</span> <span class="nx">token_then</span> <span class="nx">matched</span> <span class="nx">token_else</span> <span class="nx">matched</span>
                  <span class="o">|</span> <span class="nx">STMT</span> <span class="p">;</span>
<span class="nl">unmatched</span> <span class="p">:</span>         <span class="nx">token_if</span> <span class="nx">EXPR</span> <span class="nx">token_then</span> <span class="nx">matched</span>
                  <span class="o">|</span> <span class="nx">token_if</span> <span class="nx">EXPR</span> <span class="nx">token_then</span> <span class="nx">matched</span> <span class="nx">token_else</span> <span class="nx">unmatched</span> <span class="p">;</span>

<span class="nl">token_if</span> <span class="p">:</span>          <span class="nx">IF</span> <span class="nx">spaces</span> <span class="p">;</span>
<span class="nl">token_then</span> <span class="p">:</span>        <span class="nx">spaces</span> <span class="nx">THEN</span> <span class="nx">spaces</span> <span class="p">;</span>
<span class="nl">token_else</span> <span class="p">:</span>        <span class="nx">spaces</span> <span class="nx">THEN</span> <span class="nx">spaces</span> <span class="p">;</span>

<span class="nl">spaces</span> <span class="p">:</span>            <span class="nx">at_least_one</span><span class="p">(</span><span class="nx">SPACE</span><span class="p">)</span> <span class="p">;</span>
</code></pre></div></div>

<p>Dans le cas d’une analyse avec un <em>parser combinator</em>, il faut garder à l’esprit qu’une alternative comme celle-ci: <code class="language-plaintext highlighter-rouge">stmt : matched_eof | unmatched_eof</code>, peut être <em>complètement</em> lue. C’est-à-dire que le premier élément <code class="language-plaintext highlighter-rouge">matched_eof</code> va tenter d’être lu en premier, puis s’il y a eu une erreur, <code class="language-plaintext highlighter-rouge">unmatched_eof</code> sera lu également. L’analyse se découpe donc en plusieurs branches d’un potentiel arbre de dérivation jusqu’à en trouver une valide. Contrairement à un parseur GLR, les deux branches ne sont pas analysées simultanément. La première règle de dérivation qui fonctionne sera la bonne. Cette particularité implique que l’ordre des branches alternatives est important, dans un cas comme celui-ci, il aura une incidence sur les performances de l’analyse. La dernière figure montre respectivement l’output avec <code class="language-plaintext highlighter-rouge">matched_eof | unmatched_eof</code> et <code class="language-plaintext highlighter-rouge">unmatched_eof | matched_eof</code>.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">ext</span> <span class="nx">matched</span> <span class="nx">done</span>
<span class="nx">ext</span> <span class="nx">matched</span> <span class="nx">done</span>
<span class="nx">bounded</span> <span class="nx">stmt</span> <span class="nx">matched</span> <span class="nx">done</span>

<span class="nx">ext</span> <span class="nx">matched</span> <span class="nx">done</span>
<span class="nx">ext</span> <span class="nx">unmatched</span> <span class="nx">done</span>
<span class="nx">error</span> <span class="nx">bounded</span> <span class="nx">stmt</span> <span class="nx">unmatched</span>
<span class="nx">ext</span> <span class="nx">matched</span> <span class="nx">done</span>
<span class="nx">ext</span> <span class="nx">matched</span> <span class="nx">done</span>
<span class="nx">bounded</span> <span class="nx">stmt</span> <span class="nx">matched</span> <span class="nx">done</span>
</code></pre></div></div>]]></content><author><name>Adrien Zinger</name></author><summary type="html"><![CDATA[Lors de la conception d'une grammaire, la présence de certaines structures syntaxiques peut entraîner des ambiguïtés. Une grammaire ayant plusieurs arbres de dérivation possibles pour une même phrase est une grammaire dite ambiguë, ce qui peut compliquer l'analyse et la compréhension du langage en question]]></summary></entry><entry><title type="html">State machine and async queue (French)</title><link href="https://www.maybeuninit.com/2023/02/07/state-machine.html" rel="alternate" type="text/html" title="State machine and async queue (French)" /><published>2023-02-07T00:00:00+00:00</published><updated>2023-02-07T00:00:00+00:00</updated><id>https://www.maybeuninit.com/2023/02/07/state-machine</id><content type="html" xml:base="https://www.maybeuninit.com/2023/02/07/state-machine.html"><![CDATA[<h1 class="web">State machine and async queue (French)</h1>

<p><span class="web" style="color: #A0A0A0">[2023-02-07] #Design_pattern #State_machine #Code
</span></p>

<div class="print">
    <h1 style="text-align: center;">Machines à états (première partie)</h1>
    <h2 style="text-align: center;">Multithreading, atomicité et files non-bloquantes</h2>
    <div style="text-align: center;">Adrien Zinger, janvier 2023, maybeuninit.com</div>
</div>

<h2 id="introduction">Introduction</h2>

<p>Dans sa carrière, un bon informaticien qui tentera d’implémenter un programme
cherchera à le présenter d’une façon plus abstraite. Penser l’architecture d’un
programme est une phase importante de son développement. Une des méthodes
d’architecture consiste à imaginer son programme comme une machine à états. Car
c’est toujours possible. Cette méthode de représentation est vieille comme
l’informatique. Aujourd’hui, elle est mise en avant par des frameworks tels que
React et Redux. Mais il n’est pas nécessaire d’utiliser un framework pour qu’un
programme ressemble à une machine à états.</p>

<p>Je découperai mon travail en trois parties, et les prochains chapitres en
couvriront la première. Chacune d’entre elles aura un focus précis sur des
mécanismes disponibles en informatique et j’utiliserai l’implémentation de
machines à états comme prétexte pour parler de ces derniers. Cette partie sera
consacrée aux files d’événements qui modifient ces automates. Dans ce contexte,
les files d’événements doivent être traitées de façon séquentielle, elles
représentent donc des goulots d’étranglement pour les performances d’un
programme. Je ne dis pas qu’il soit effectivement important de se soucier
autant des performances d’un automate. Cependant, traiter ce sujet offre
l’occasion de regarder de plus près ce qui peut être utilisé dans un programme
multithreadé. Je ne peux pas non plus dire dans quels contextes ces mécanismes
sont réellement appliqués, ils n’en restent pas moins intéressants. Mais ils
existent et sont utilisés, pour des raisons parfois arbitraires, à cause de
croyances personnelles, ou bien plus raisonnablement, du fait des connaissances
poussées du sujet. Parfois, plus simplement, ils sont présents parce qu’un
sous-problème nécessite une attention particulière et doit être le plus
performant possible, on essaie donc plusieurs méthodes, souvent empiriquement.
Si j’échoue à faire comprendre pour quelles raisons une machine à états
correspond à votre cas d’usage, ces chapitres pourront être intéressants au
moins pour les sujets variés qu’ils abordent.</p>

<p>Je ne présenterai donc pas tout à fait, comme pourrait l’indiquer le titre
trompeur, les machines à états. Cependant, pour le contexte j’évoquerai tout de même une
introduction sur l’état de l’art aujourd’hui. J’y ajouterai quelques
opinions personnelles, également partagées par quelques collègues et amis, bien que subjectives. Pour l’introduction, j’utiliserai un
langage qui est habituellement plus adapté pour parler de parseurs (analyseurs
syntaxique). Même si un analyseur est un sous-type de machine à états, le
vocabulaire sera suffisant. Je parlerai donc de grammaires, de contextes, de
conflits, etc.</p>

<p>Un chapitre sur deux en moyenne sera dédié au multithreading, aux structures de
données non-bloquantes. En particulier des files d’attente, des implémentations
de <em>mpsc</em> (<em>Multiple Producer Single Consumer</em>), d’opérations atomiques et de
mécanismes de synchronisation. Ce sujet est bien plus complexe qu’il ne
le paraît. Changer une structure synchrone en une structure
non-bloquante asynchrone n’est pas anodin et peut avoir un fort impacte sur un
programme. Parfois, l’espace mémoire que la structure prendra sera bien plus
grand que l’original. Parfois, il faudra faire des concessions sur les
performances et se poser les bonnes questions.</p>

<p>Quelques exemples en C, Rust et Pseudocode accompagneront mon propos. Le code
complet est disponible en annexe. Je vous recommande toutefois de ne pas trop
vous y attarder et de considérer qu’il n’y a pas de réponse parfaite et encore
moins d’implémentation unique à une solution. Aussi, j’espère que vous me
pardonnerez les simplifications que je fais en Rust étant un langage plutôt
verbeux, j’ai dû tailler quelques morceaux pour en extraire l’essentiel.</p>

<p>J’en profite pour vous prévenir que je suis conscient de maîtriser certains
aspects et pas d’autres. Même si j’ai le sentiment d’être dans le vrai,
n’hésitez pas à me corriger si vous rencontrez des erreurs. Il y en aura
forcement, même après une centaine de relectures. Je serai heureux de recevoir
les remarques ainsi que les opinions par mail
(<code class="language-plaintext highlighter-rouge">zinger.ad@gmail.com</code>) on dans un commentaire sur mon github.</p>

<h2 id="chapitre-1---les-machines-à-états">Chapitre 1 - Les machines à états</h2>

<blockquote>
  <p>Ce que tu peux faire de mieux pour ton programme, c’est
d’en faire une machine à états.</p>
</blockquote>

<p>Dans un projet, on souhaite une machine à états quand une partie du programme
gère un contexte global ou temporaire, subit des modifications lors d’appels
exterieurs ou doit réagir à différentes entrées et retourner un résultat
cohérent avec celles-ci, en tenant compte d’un historique. Une telle machine
peut être utilisée pour modeler un composant d’un système distribué par
exemple, et même le système complet. Chaque état, dans ce cas, peut contenir un
snapshot à un instant T qui inclue l’état de la mémoire des composants
(processeurs) ainsi que les messages en transit. Plus généralement, on
souhaite une machine à états lorsqu’une fonction donne une sortie différente
après chaque appel. On remarque que les itérateurs et les générateurs sont
aussi des genres de machine à états.</p>

<p>Il y a différentes façons d’aborder le problème. La façon scolaire, linéaire
que la plupart des raisonnements humains vont produire. Cette façon de faire
pourra, entre autres, ressembler à un analyseur LL ou LR car les
implémentations peuvent être très similaires. Souvent, ces deux méthodes ne se
différencient que dans les structures qu’elles utilisent dans l’implémentation.
On y trouvera, dans tous les cas la logique suivante : “si j’ai tel événement
dans tel contexte, je passe à tel état suivant”. Au début de mes études, je
codais de nombreuses fonctions qui s’appelaient les unes les autres, pleines de
conditions et de branchements.</p>

<p>Un raisonnement de la sorte, avec une implémentation bien linéaire, des états
qui s’empilent puis se réduisent, est efficace si on souhaite développer
rapidement un petit morceau de code. Mais cela devient vite ingérable dans une
application qui traversera beaucoup d’états, si en plus aucun des branchements
ne peut être auto-généré ou encore que les transitions se complexifient. Idem,
si le projet change ses grammaires ou s’il s’avère qu’on commence à y trouver
des conflits.</p>

<p>Depuis longtemps, on élude ces problèmes en utilisant des générateurs de
parseurs. Vous avez peut-être déjà entendu parler de YACC et LEX.
Ce genre de générateur existe dans de nombreux langages et sous de nombreuses
formes. Il me semble qu’aujourd’hui, leur utilisation est moins répandue ou
moins célèbre. Dans mon entourage, parmi mes amis et collègues, je trouve peu
de gens à qui cela laisse de bons souvenirs. Pourtant, selon moi, c’est la
meilleure solution pour générer des machines à états encore aujourd’hui. Se
plonger dans une grammaire sous le format BNF, aussi ennuyeux que cela puisse être, vous
fera gagner une base de code propre et un temps considérable. Toute méthode a
ses avantages et ses inconvénients. Bien sûr, dans certains cas, il sera plus
simple d’écrire rapidement un analyseur à la main ou en utilisant une
bibliothèque tierce.</p>

<p>Depuis quelques temps, on développe aussi des analyseurs par petits morceaux. Ces
combinaisons de parseurs ont des bons côtés. Déjà, on ne dépend pas d’un
générateur et, dans le meilleur des cas, on ne dépend pas non plus d’une
bibliothèque. Le développement est linéaire et correspond plus au attente d’un
développeur classique : je lis, je change d’état. Les états sont des parseurs,
des fonctions. Bien sûr, on risque de retomber dans le piège des nombreuses
fonctions pleines de conditions, il faut faire attention.</p>

<p>Ensuite, il y a la manière React ou Redux. Car en faisant du React, on fait des
parseurs, ou plutôt, des machines à états. L’un ou l’autre, c’est presque
pareil.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// green thread 1</span>
<span class="kd">function</span> <span class="nx">state_machine</span><span class="p">()</span> <span class="p">{</span>
    <span class="c1">// création de la machine à états</span>
    <span class="kd">let</span> <span class="p">(</span><span class="nx">state</span><span class="p">,</span> <span class="nx">dispatch</span><span class="p">)</span> <span class="o">=</span> <span class="nx">use_state</span><span class="p">(</span><span class="nx">reducer_function</span><span class="p">,</span> <span class="nx">state_1</span><span class="p">);</span>
    <span class="nx">foo</span><span class="p">(</span><span class="nx">dispatch</span><span class="p">).</span><span class="nx">then</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{});</span>
<span class="p">}</span>

<span class="c1">// green thread 2</span>
<span class="k">async</span> <span class="kd">function</span> <span class="nx">foo</span><span class="p">(</span><span class="nx">dispatch</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nx">state2</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">recv_async_call</span><span class="p">();</span>
    <span class="nx">dispatch</span><span class="p">(</span><span class="nx">state2</span><span class="p">);</span> <span class="c1">// changement d'état</span>
<span class="p">}</span>
</code></pre></div></div>

<p>React permet de recharger des composants (des machines à états) avec des
nouveaux états. On a à disposition des fonctions comme <code class="language-plaintext highlighter-rouge">useReducer</code> et
<code class="language-plaintext highlighter-rouge">useState</code>, qui sont les plus utilisées. Ces méthodes permettent chacune de
créer une fonction de mise à jour (dispatch) en donnant pour paramètres une
valeur initiale et une routine de réduction : <code class="language-plaintext highlighter-rouge">(current_state, action) =&gt;
new_state</code>. Une fonction de réduction permet de créer un nouvel état à partir
de l’état courant et d’un événement, telle qu’une entrée utilisateur. Pouvoir
donner cette fonction en argument permet de centraliser les comportements
complexes en fonction d’un contexte. Avec <code class="language-plaintext highlighter-rouge">useState</code>, on se limite à prendre
pour argument un état initial, il utilise sa propre fonction de réduction où le
paramètre <code class="language-plaintext highlighter-rouge">action</code> sera le nouvel état.</p>

<!-- Ajouts apres relecture Yvan -->
<p>L’idée n’est pas tout a fait de reproduire <em>React</em> dans son integralité, ni
d’entrer dans des concepts d’effets algébriques, mais bien de reprendre
certaines bases qui pourraient donner des résultats visuellement identiques.
Par exemple, le fait que <code class="language-plaintext highlighter-rouge">useState</code> soit composé d’un <code class="language-plaintext highlighter-rouge">useReducer</code> est bien
exacte. Voici un extrait de l’implémentation actuelle qui, si l’action est
une fonction, retourne le résultat de celle-ci, sinon retourne l’objet de
l’action. Cette routine est le réducteur utilisé à l’appel de <code class="language-plaintext highlighter-rouge">useState</code>.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">basicStateReducer</span><span class="o">&lt;</span><span class="nx">S</span><span class="o">&gt;</span><span class="p">(</span><span class="nx">state</span><span class="p">:</span> <span class="nx">S</span><span class="p">,</span> <span class="nx">action</span><span class="p">:</span> <span class="nx">BasicStateAction</span><span class="o">&lt;</span><span class="nx">S</span><span class="o">&gt;</span><span class="p">):</span> <span class="nx">S</span> <span class="p">{</span>
  <span class="k">return</span> <span class="k">typeof</span> <span class="nx">action</span> <span class="o">===</span> <span class="dl">'</span><span class="s1">function</span><span class="dl">'</span> <span class="p">?</span> <span class="nx">action</span><span class="p">(</span><span class="nx">state</span><span class="p">)</span> <span class="p">:</span> <span class="nx">action</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<!-- -->
<p>Le fonctionnement d’une machine à états similaire React est alors décrit par
des structures génériques dans une file et une fonction de transition si
nécessaire. Grâce à cette méthode, nous pouvons utiliser la généricité afin de
simplifier l’implémentation finale.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">onStateChange_Tests</span><span class="p">(</span><span class="nx">state</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">if</span> <span class="p">(</span><span class="nx">state</span><span class="p">.</span><span class="nx">view</span> <span class="o">==</span> <span class="dl">"</span><span class="s2">view1</span><span class="dl">"</span><span class="p">)</span> <span class="k">return</span> <span class="nx">showView1</span><span class="p">();</span>
  <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">state</span><span class="p">.</span><span class="nx">view</span> <span class="o">==</span> <span class="dl">"</span><span class="s2">view2</span><span class="dl">"</span><span class="p">)</span> <span class="k">return</span> <span class="nx">showView2</span><span class="p">();</span>
  <span class="k">else</span> <span class="k">return</span> <span class="nx">showView3</span><span class="p">();</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">onStateChange_Generique</span><span class="p">(</span><span class="nx">state</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">return</span> <span class="nx">state</span><span class="p">.</span><span class="nx">showView</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="chapitre-2---utiliser-une-machine-à-état">Chapitre 2 - Utiliser une machine à état</h2>

<p>Une machine à états est flexible, on l’adapte en fonction du besoin. Un
itérateur, un générateur ou encore un analyseur sont des types de machines à
états. Parfois, un simple appel à un timeout peut en cacher une :
“en cours -&gt; annulé”, “ouvert -&gt; fermé”. Mais parmi tous, l’analyseur est un
cas particulier. Un parseur suppose une fin à ses états. Que le programme soit
écrit à l’aide d’un générateur ou avec la méthode des combinaisons, on attend
des états qu’ils se résolvent et, pour finir, qu’ils arrivent à l’état ultime :
la sortie du programme avec succès.</p>

<p>Pourtant, avec la méthode React, on peut écrire des itérateurs, des
parseurs et toute sorte de machines à états finies et infinies. C’est pour cette
raison qu’elle est extrêmement efficace pour la gestion d’une application.
Faire avancer ses états avec React se résume à empiler des événements et les
traiter un par un afin d’appliquer les modifications adéquates.</p>

<p>Les morceaux de codes qui suivront font partie d’une expérience : créer une
bibliothèque de zéro, avec les mêmes attentes qu’on pourrait avoir de React. Le
sujet de l’expérience ici sera un programme simpliste où j’implémente un <em>echo</em>
volontairement complexe (à ne pas refaire chez soi).</p>

<p>Voici le comportement attendu :</p>

<ol>
  <li>la sortie standard affichera <code class="language-plaintext highlighter-rouge">waiting for an entry</code>.</li>
  <li><code class="language-plaintext highlighter-rouge">you wrote: ${entrée}</code> suivit de <code class="language-plaintext highlighter-rouge">Can you write something else?</code>.</li>
  <li><code class="language-plaintext highlighter-rouge">you wrote: ${entrée}</code> puis <code class="language-plaintext highlighter-rouge">Can you write something else? (${compteur})</code>.
 Puis répéter à partir de 3.</li>
</ol>

<p>Le programme devra s’arrêter à la lecture du mot clef <em>“exit”</em>. Et avancera à chaque
lecture d’une entrée utilisateur.</p>

<p>Je commence par créer une structure <code class="language-plaintext highlighter-rouge">State</code> représentant un état contenant une
méthode appliquant une des étapes du programme et certaines variables
contextuelles. La méthode associée dynamiquement variera lors d’une transition
ou bien pourra être modifiée, puis validée avec une fonction <code class="language-plaintext highlighter-rouge">dispatch</code> que
proposera cette logique. Chacune des méthodes sera représentative de l’état du
programme (1, 2 ou 3 et plus). Visuellement, il suffira de lire une fonction
pour comprendre ce qu’un état va avoir comme effet de bord. Pour le
développement du projet, un diagramme d’états suffira pour comprendre la
logique de l’application, ce qui est très agréable.</p>

<p align="center">
  <img width="400" src="/assets/img/state_machine_1/diagrame_d_etats_1.png" />
</p>

<p>La figure ci-dessous montre l’implémentation de chacune des étapes de
l’automate. Les lignes A2 et B3 montrent comment changer d’état après une
exécution. La ligne C3 modifie un contexte en incrémentant un compteur pour
l’itération suivante. Les autres lignes sont des effets de bord.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">step_1</span><span class="p">(</span><span class="k">struct</span> <span class="n">State</span> <span class="o">*</span><span class="n">self</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"waiting for an entry</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>                       <span class="c1">// A1</span>
    <span class="n">self</span><span class="o">-&gt;</span><span class="n">step</span> <span class="o">=</span> <span class="n">step_2</span><span class="p">;</span>                                    <span class="c1">// A2</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">step_2</span><span class="p">(</span><span class="k">struct</span> <span class="n">State</span> <span class="o">*</span><span class="n">self</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"you wrote: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>                              <span class="c1">// B1</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Can you write something else?</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">self</span><span class="o">-&gt;</span><span class="n">val</span><span class="p">);</span>   <span class="c1">// B2</span>
    <span class="n">self</span><span class="o">-&gt;</span><span class="n">step</span> <span class="o">=</span> <span class="n">step_n</span><span class="p">;</span>                                    <span class="c1">// B3</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">step_3_and_more</span><span class="p">(</span><span class="k">struct</span> <span class="n">State</span> <span class="o">*</span><span class="n">self</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"you wrote: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>                              <span class="c1">// C1</span>
    <span class="n">printf</span><span class="p">(</span><span class="s">"Can you write something else? (%i)</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span>          <span class="c1">// C2</span>
        <span class="n">self</span><span class="o">-&gt;</span><span class="n">val</span><span class="p">,</span> <span class="o">++</span><span class="p">(</span><span class="n">self</span><span class="o">-&gt;</span><span class="n">count</span><span class="p">));</span>                        <span class="c1">// C3</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Il est important de noter qu’ici plusieurs lignes modifient la valeur de
l’état. Ces valeurs sont modifiées en prévision de l’itération suivante de mon
programme. Autrement dit, je ne modifie pas mon état actuel, mais je construis
l’état suivant. Dans certains cas, cette façon de faire peut poser problème,
notamment si le programme utilise plusieurs threads qui ont accès à cette
variable parallèlement. Parmi les problèmes qu’on peut rencontrer, dans le
multithreading, le fait de rendre l’état courant immutable ou limiter sa
mutabilité devient une nécessité. Ne touchez pas à l’état courant,
construisez-en un nouveau ou entourez-le de <em>mutexes</em>. J’évoque le terme
d’itération dans ce paragraphe. En quelques mots, le coeur de mon programme est
une boucle infinie, qui à chaque nouvelle mise à jour exécutera la même
fonction. La logique ne change pas, l’état si.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">state_machine</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">Reaction</span> <span class="o">*</span><span class="n">re</span> <span class="o">=</span> <span class="n">use_state</span><span class="p">(</span><span class="n">make_init_state</span><span class="p">);</span>
    <span class="k">struct</span> <span class="n">State</span> <span class="o">*</span><span class="n">st</span> <span class="o">=</span> <span class="n">re</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">st</span><span class="o">-&gt;</span><span class="n">before</span><span class="p">(</span><span class="n">st</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">pthread_join</span><span class="p">(</span><span class="n">st</span><span class="o">-&gt;</span><span class="n">scan</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">EXIT_SM</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">st</span><span class="o">-&gt;</span><span class="n">step</span><span class="p">(</span><span class="n">st</span><span class="p">);</span>
    <span class="n">async_scan</span><span class="p">(</span><span class="n">re</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">CONTINUE_SM</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Voici comment une machine à états infinie pourrait s’implémenter. La complexité
(absurde) de l’exemple par rapport à l’objectif montre comment on peut se
défaire d’une série de conditions et d’intrications de fonctions. Par exemple,
l’optimisation de la routine <code class="language-plaintext highlighter-rouge">before</code> qui en premier lieu retourne forcément 0,
n’ayant aucune entrée à lire, ne fera d’abord rien, puis se mettra à jour pour faire
quelque chose. Dans un projet plus réaliste, ces petites différences sont
importantes. Elle permet de contrôler à chaque état les effets de bord
nécessaires ou superflus, variants et invariants.</p>

<h2 id="chapitre-3---la-file-détats">Chapitre 3 - La file d’états</h2>

<p>Abordons une partie importante de l’exemple : la lecture de
l’entrée utilisateur. C’est-à-dire l’endroit où j’appelle la méthode <code class="language-plaintext highlighter-rouge">dispatch</code>
associée à la machine à états. Cette méthode ajoute dans une file un nouvel
objet associé à une fonction de réduction, selon qu’on ai utilisé <code class="language-plaintext highlighter-rouge">use_state</code>
ou <code class="language-plaintext highlighter-rouge">use_reducer</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="o">*</span><span class="nf">scan</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">_re</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// Récupération de la machine à états à altérer</span>
    <span class="k">struct</span> <span class="n">Reaction</span> <span class="o">*</span><span class="n">re</span> <span class="o">=</span> <span class="p">(</span><span class="k">struct</span> <span class="n">Reaction</span> <span class="o">*</span><span class="p">)</span><span class="n">_re</span><span class="p">;</span>
    <span class="k">struct</span> <span class="n">State</span> <span class="o">*</span><span class="n">new_state</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">State</span><span class="p">));</span>
    <span class="n">memcpy</span><span class="p">(</span><span class="n">new_state</span><span class="p">,</span> <span class="n">re</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="k">struct</span> <span class="n">State</span><span class="p">));</span>
    <span class="kt">int</span> <span class="n">_</span> <span class="o">=</span> <span class="n">scanf</span><span class="p">(</span><span class="s">"%299s"</span><span class="p">,</span> <span class="n">new_state</span><span class="o">-&gt;</span><span class="n">val</span><span class="p">);</span>
    <span class="n">dispatch</span><span class="p">(</span><span class="n">re</span><span class="p">,</span> <span class="n">new_state</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Ce modèle de machine à états enfile des objets pour les traiter de façon
synchrone, mais rien n’empêche que l’accumulation des événements soit
asynchrone ou parallèle. Il est donc important de se poser quelques questions
sur la résistance du modèle face au parallélisme.</p>

<p>Dans ce programme simple, j’ai de la chance pour deux raisons. La première est
que <code class="language-plaintext highlighter-rouge">scanf</code> en C a une implémentation telle que, même si plusieurs threads
écoutent en même temps, seulement l’un d’entre eux se réveillera avec un
buffer. Mais imaginons que le programme écoute plusieurs entrées différentes,
comme des appels réseau ou des notifications de l’OS. Les opérations d’enfilage
et de défilage peuvent être concurrentes et poser des problèmes de
synchronisation.</p>

<p>Pour résoudre les problèmes liés au parallélisme dans un modèle de machine à
états, on peut utiliser des techniques de partage de données appelées <em>X
producteur(s) Y consommateur(s)</em> où <em>X</em> et <em>Y</em> peuvent prendre la forme de
“unique” ou “multiple”. Il existe de nombreuses implémentations et approches
différentes, au moins une par bibliothèque standard. Celle qui est implémentée
dans la bibliothèque Reagir, la mienne, n’est peut-être pas la plus efficace,
mais elle est facile à comprendre pour commencer.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="kt">void</span> <span class="nf">send_state</span><span class="p">(</span><span class="k">struct</span> <span class="n">Entry</span> <span class="n">e</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">Reagir</span> <span class="o">*</span><span class="n">re</span> <span class="o">=</span> <span class="n">e</span><span class="p">.</span><span class="n">rea</span><span class="o">-&gt;</span><span class="n">re</span><span class="p">;</span>                       <span class="c1">// S1</span>
    <span class="n">pthread_mutex_lock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">);</span>                      <span class="c1">// S2</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">queue_len</span> <span class="o">==</span> <span class="n">QUEUE_MAX_LEN</span><span class="p">)</span>               <span class="c1">// S3</span>
        <span class="n">pthread_cond_wait</span><span class="p">(</span><span class="o">&amp;</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">pop_condvar</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">);</span> <span class="c1">// S4</span>
    <span class="n">re</span><span class="o">-&gt;</span><span class="n">queue</span><span class="p">[</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">push_ptr</span><span class="p">]</span> <span class="o">=</span> <span class="n">e</span><span class="p">;</span>                         <span class="c1">// S5</span>
    <span class="n">re</span><span class="o">-&gt;</span><span class="n">push_ptr</span> <span class="o">=</span> <span class="p">(</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">push_ptr</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="n">QUEUE_MAX_LEN</span><span class="p">;</span>   <span class="c1">// S6</span>
    <span class="n">re</span><span class="o">-&gt;</span><span class="n">queue_len</span><span class="o">++</span><span class="p">;</span>                                     <span class="c1">// S7</span>
    <span class="n">pthread_cond_signal</span><span class="p">(</span><span class="o">&amp;</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">push_condvar</span><span class="p">);</span>              <span class="c1">// S8</span>
    <span class="n">pthread_mutex_unlock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">);</span>                    <span class="c1">// S9</span>
<span class="p">}</span>

<span class="k">static</span> <span class="k">struct</span> <span class="n">Entry</span> <span class="nf">receive_state</span><span class="p">(</span><span class="k">struct</span> <span class="n">Reagir</span> <span class="o">*</span><span class="n">re</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">pthread_mutex_lock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">);</span>                      <span class="c1">// R1</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">queue_len</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>                           <span class="c1">// R2</span>
        <span class="n">pthread_cond_wait</span><span class="p">(</span><span class="o">&amp;</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">push_condvar</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">);</span><span class="c1">// R3</span>
    <span class="k">struct</span> <span class="n">Entry</span> <span class="n">e</span> <span class="o">=</span> <span class="n">re</span><span class="o">-&gt;</span><span class="n">queue</span><span class="p">[</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">pop_ptr</span><span class="p">];</span>             <span class="c1">// R4</span>
    <span class="n">re</span><span class="o">-&gt;</span><span class="n">pop_ptr</span> <span class="o">=</span> <span class="p">(</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">pop_ptr</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="n">QUEUE_MAX_LEN</span><span class="p">;</span>     <span class="c1">// R5</span>
    <span class="n">re</span><span class="o">-&gt;</span><span class="n">queue_len</span><span class="o">--</span><span class="p">;</span>                                     <span class="c1">// R6</span>
    <span class="n">pthread_cond_signal</span><span class="p">(</span><span class="o">&amp;</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">pop_condvar</span><span class="p">);</span>               <span class="c1">// R7</span>
    <span class="n">pthread_mutex_unlock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">re</span><span class="o">-&gt;</span><span class="n">mutex</span><span class="p">);</span>                    <span class="c1">// R8</span>
    <span class="k">return</span> <span class="n">e</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">dispatch</span><span class="p">(</span><span class="k">struct</span> <span class="n">Reaction</span> <span class="o">*</span><span class="n">rea</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">arg</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">Entry</span> <span class="n">e</span> <span class="o">=</span> <span class="p">{(</span><span class="k">struct</span> <span class="n">PrivReaction</span> <span class="o">*</span><span class="p">)</span><span class="n">rea</span><span class="p">,</span> <span class="n">arg</span><span class="p">};</span>
    <span class="n">send_state</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Lorsqu’on appelle la fonction <code class="language-plaintext highlighter-rouge">dispatch</code>, on créé une nouvelle entrée qui sera
traitée par la bibliothèque pour passer d’un état à un autre. La fonction
<code class="language-plaintext highlighter-rouge">dispatch</code> prend en argument la structure <code class="language-plaintext highlighter-rouge">Reaction</code> qui représente la machine
à états que l’on souhaite altérer, ainsi qu’un second argument qui peut être un
nouvel état (si on utilise <code class="language-plaintext highlighter-rouge">use_state</code>) ou une action (si on utilise
<code class="language-plaintext highlighter-rouge">use_reducer</code>). Cela permet de continuer à avancer pas à pas en enfilant des
fonctions de réduction qui seront appelées séquentiellement avec leurs
arguments. En d’autres termes, cela consiste à enfiler des fonctions de
réduction et l’argument d’événement <code class="language-plaintext highlighter-rouge">action</code>.</p>

<p>Prenons un peu le temps de lire l’algorithme de la figure précédente. On
remarque que ce code contient plusieurs verrous. Un verrou coûte du temps au
processeur. Il est préférable, si possible, d’éviter d’en invoquer un. Bon,
cette implémentation est peut être suffisante pour mon exemple.</p>

<p>Le deuxième point qui me rend chanceux dans cette implémentation, c’est que
l’utilisation que je fais de ma machine à états <em>est synchrone</em>. Même si
j’utilise deux threads différents. Je ne lis pas d’entrée utilisateur pendant
l’exécution de la boucle de la machine à états, ou même avant. À aucun moment,
je peux envoyer un événement ET en recevoir simultanément. Les lignes S2, S9 R1
et R8 sont donc inutiles dans ce cas. Malgré tout, les lignes S3, S4, S8 et R2,
R3 et R7 sont encore nécessaires pour ne pas faire boucler le CPU sans raisons.
Si vous n’êtes pas familier avec ce mécanisme, je vous propose de vous
documenter sur les variables conditionnelles et leurs usages avant de
continuer.</p>

<!-- Un petit paragraphe sur les variables conditionnelles devrait
     être en bonus -->

<p>Même si mon programme communiquait avec d’autres, si je m’assure d’un ping pong
où chaque instance attend la réponse de l’autre, je peux écrire ces instances
sans aucun appel de <code class="language-plaintext highlighter-rouge">lock unlock</code>. Autrement dit, tant qu’on peut considérer
que l’ensemble du système fonctionne sur un unique thread en additionnant les
exécutions concurrentes, on peut se passer de verrou. Le fait d’avoir une
utilisation synchrone de cette file est l’unique justification valable pour
retirer les <em>mutexes</em>. Des appels parallèles auraient des résultats
imprévisibles. Par mesure de sécurité, il faut toujours entourer les variables
conditionnelles par des verrous. Tenez ça pour une règle d’or.</p>

<p>Dans ce cas, je retire quelques utilisations de mutexes et ça marche. Mais nous
nous bornerons à des systèmes <em>mono-threadé</em>. L’implémentation naïve ne suffit
pas dans les cas suivants. Si on souhaite quelque chose de plus puissant qui
nous autorise des lectures et écritures parallèles, il faut se tourner vers des
structures plus efficaces. Dans un contexte où on recevrait des évenements trop
rapidement, une structure de données non-bloquante pourrait être intéressante.
Il y a un grand nombre d’implémentation possible, encore, à commencer par celle
qui utilise deux mutexes différents pour la tête de file et son bout. Les
producteurs se partageraient un verrou et le consommateur sera plus rapide à
lire, ayant le monopole sur le défilement.</p>

<p>Plus rapide encore, une version de la file de <em>Michael &amp; Scott</em> propose une
solution n’utilisant aucun mutex. L’algorithme tire avantage des capacités
atomiques du processeur. En d’autres termes, la lecture ou l’écriture d’une
variable sera organisé parmi les différents threads dans un ordre spécifié.</p>

<h2 id="chapitre-4---rappel-atomique">Chapitre 4 - Rappel atomique</h2>

<p>Une opération atomique, c’est lire, écrire, effectuer une opération basique
comme un <code class="language-plaintext highlighter-rouge">ET</code> ou un <code class="language-plaintext highlighter-rouge">OU</code>, sur une petite partie de la mémoire comme par exemple
là où se trouve un entier. Cette opération garantie qu’aucun autre thread ne va
tenter de lire ou écrire pendant le temps de l’opération. Enfin, ces
opérations garantissent que le processeur respectera un certain ordre défini
par les instructions, éloignant les comportements indéfinis. Ainsi,
un programme comme décrit ci-dessous aura une fin déterministe alors qu’un
programme similaire avec une incrémentation non-atomique serai
non-deterministe.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">add</span><span class="p">(</span><span class="n">i</span><span class="p">:</span> <span class="n">AtomicInt</span><span class="o">*</span><span class="p">):</span>
    <span class="nf">fetch_add</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>

<span class="nf">main</span><span class="p">():</span>
    <span class="k">let</span> <span class="n">i</span> <span class="o">=</span> <span class="nn">AtomicInt</span><span class="p">::</span><span class="nf">new</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
    <span class="k">let</span> <span class="n">th1</span> <span class="o">=</span> <span class="nn">Thread</span><span class="p">::</span><span class="nf">spawn</span><span class="p">({</span> <span class="nf">add</span><span class="p">(</span><span class="o">&amp;</span><span class="n">i</span><span class="p">)</span> <span class="p">});</span>
    <span class="k">let</span> <span class="n">th2</span> <span class="o">=</span> <span class="nn">Thread</span><span class="p">::</span><span class="nf">spawn</span><span class="p">({</span> <span class="nf">add</span><span class="p">(</span><span class="o">&amp;</span><span class="n">i</span><span class="p">)</span> <span class="p">});</span>
    <span class="nf">join</span><span class="p">(</span><span class="n">th1</span><span class="p">,</span> <span class="n">th2</span><span class="p">);</span>
    <span class="nd">assert!</span><span class="p">(</span><span class="n">i</span> <span class="o">==</span> <span class="mi">2</span><span class="p">);</span>
</code></pre></div></div>

<!-- Ajout après relecture Yvan -->
<p>On associera toujours une opération atomique à ce qu’on appelle un
ordonnancement. Avant de poursuivre ce chapitre, il est important d’en préciser
quelques caractéristiques. Par exemple, une opération de lecture, également
appelée chargement, peut être soumise à un ordonnancement nommé <code class="language-plaintext highlighter-rouge">ACQUIRE</code>.
Cette opération respectera certaines contraintes, lesquelles sont :</p>

<ol>
  <li>Il est impossible pour le processeur de réordonner les lectures ou écritures
après le chargement de la variable.</li>
  <li>Les écritures effectuées dans d’autres threads sont visibles pour le thread
lecteur.</li>
</ol>

<p>La première règle est garantie par des instructions de barrières mémoire qui
permettent de maintenir un ordre cohérent entre le programme écrit et son
interprétation par le processeur. Le deuxième point est plus complexe, car il
permet au thread courant d’établir un ordre chronologique et les relations
<em>“arrive avant”</em> entre les accès à une variable. Le thread qui charge une
variable dans une zone mémoire “A” interprètera chronologiquement chaque
écriture dans des threads parallèles afin de trouver la dernière valeur dans A.
Cependant, les relations <em>arrivé avant</em> sont des interprétations qui ne
concernent que le thread courant. Du fait, d’autres threads peuvent avoir une
vision chronologique différente des événements. Les autres ordonnancements
mentionnés plus tard ont des comportements plus ou moins similaires.
<!-- --></p>

<p>De base, sur un processeur Intel, tout mouvement, selon ce que l’on comprend,
est atomique. Prenons l’instruction <code class="language-plaintext highlighter-rouge">mov</code> sur <code class="language-plaintext highlighter-rouge">x86</code>. Cette instruction est
courante dans un programme, elle peut être produite par une assignation de
variable ou encore un passage d’argument. Cette instruction permet selon son
utilisation de copier une valeur ou de copier l’adresse de cette valeur. C’est
la différence entre un déplacement <em>par copie</em> ou <em>par référence</em>. Elle peut
être utilisée pour lire ou écrire, selon le sens dans lequel on place les
arguments. Lorsqu’une instruction de lecture est exécutée, elle a un
comportement similaire à l’ordonnancement défini par <code class="language-plaintext highlighter-rouge">ACQUIRE</code> et lorsqu’une
instruction d’écriture est exécutée, elle a un comportement similaire à
l’ordonnancement défini par <code class="language-plaintext highlighter-rouge">RELEASE</code>. Ce, sans avoir besoin de préciser quoi
que ce soit. En fait sur <code class="language-plaintext highlighter-rouge">x86</code>, l’ordonnancement <code class="language-plaintext highlighter-rouge">RELAXED</code> est chimérique.
C’est-à-dire que les compilations d’opérations atomiques avec le flag <code class="language-plaintext highlighter-rouge">RELAXED</code>
produiront le même résultat que des opérations dites non-atomique ou des
opérations atomiques <code class="language-plaintext highlighter-rouge">ACQUIRE/RELEASE</code>.</p>

<p>Toutes les opérations de lecture et d’écriture, dans un certain sens, sont donc
“atomiques” sur <code class="language-plaintext highlighter-rouge">x86</code>. Mais ce n’est pas le cas pour tous les processeurs. Sur
certains macs, ou quelques consôles de jeu, qui ont un processeur <code class="language-plaintext highlighter-rouge">ARM</code>, on
devra utiliser des instructions telle que <code class="language-plaintext highlighter-rouge">dmb</code> (data memory barrier) pour
préciser un ordre <code class="language-plaintext highlighter-rouge">ACQUIRE/RELEASE</code>. L’instruction <code class="language-plaintext highlighter-rouge">dmb</code> garantit que toutes
les instructions de lecture ou écriture en mémoire exécutées avant elle soient
bien terminées avant que de passer à d’autre instructions. Il convient alors de
dire, en écrivant du code plus haut niveau, comme du <em>Rust</em> ou du <em>C</em>, que
toutes les opérations sont non-atomique tant que le développeur ne le précise pas.</p>

<!-- Ajout apres relecture d'Yvan -->
<blockquote>
  <p>En ce qui concerne les variables volatile, il n’y a pas de différence
particulière. Cependant, le compilateur tachera de toujours utiliser l’adresse
réelle de la variable sans optimiser grâce à des variables temporaires ou en
les remplaçant par une logique plus appropriée, après du tree shaking par
exemple. Le compilateur est donc simplement informé du fait que la variable est
sucéptible de changer dans d’autres exécutions parallèles. Il est important
préciser que les instructions produites resteront souvent les mêmes qu’avec des
variables globales basiques, et que la compilation ne génèrera aucune barrière
mémoire comme elle pourrait le faire avec des variables atomiques. Cela dit,
l’utilisation de ce genre de mot-clef se perd avec le temps et les impactes
peuvent varier d’un langage à un autre.
<!--  --></p>
</blockquote>

<p>Le processeur, pour plusieurs raisons, peut avoir le droit de superposer des
opérations sur un même thread. C’est ce qu’on appelle l’out-of-order (<em>OOO</em>).
Ce qui peut rendre un programme avec des exécutions parallèles difficiles à se
représenter et donc complexes à développer. Avec des opérations atomiques ainsi
que les flags <code class="language-plaintext highlighter-rouge">Acquire</code>, <code class="language-plaintext highlighter-rouge">Release</code>, <code class="language-plaintext highlighter-rouge">AcqRel</code> et <code class="language-plaintext highlighter-rouge">SeqCst</code>, on peut forcer le
processeur à ne plus superposer certaines lectures et écritures. On peut aussi
forcer un certain ordre, ou du moins certaines contraintes.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">while</span> <span class="p">(</span><span class="n">ip</span> <span class="o">&lt;</span> <span class="n">iend</span><span class="o">-</span><span class="mi">15</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">U32</span> <span class="n">c</span> <span class="o">=</span> <span class="n">cached</span><span class="p">;</span> <span class="n">cached</span> <span class="o">=</span> <span class="n">MEM_read32</span><span class="p">(</span><span class="n">ip</span><span class="p">);</span> <span class="n">ip</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
    <span class="n">Counting1</span><span class="p">[(</span><span class="n">BYTE</span><span class="p">)</span> <span class="n">c</span>     <span class="p">]</span><span class="o">++</span><span class="p">;</span>
    <span class="n">Counting2</span><span class="p">[(</span><span class="n">BYTE</span><span class="p">)(</span><span class="n">c</span><span class="o">&gt;&gt;</span><span class="mi">8</span><span class="p">)</span> <span class="p">]</span><span class="o">++</span><span class="p">;</span>
    <span class="n">Counting3</span><span class="p">[(</span><span class="n">BYTE</span><span class="p">)(</span><span class="n">c</span><span class="o">&gt;&gt;</span><span class="mi">16</span><span class="p">)]</span><span class="o">++</span><span class="p">;</span>
    <span class="n">Counting4</span><span class="p">[</span>       <span class="n">c</span><span class="o">&gt;&gt;</span><span class="mi">24</span> <span class="p">]</span><span class="o">++</span><span class="p">;</span>
    <span class="n">c</span> <span class="o">=</span> <span class="n">cached</span><span class="p">;</span> <span class="n">cached</span> <span class="o">=</span> <span class="n">MEM_read32</span><span class="p">(</span><span class="n">ip</span><span class="p">);</span> <span class="n">ip</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
    <span class="n">Counting1</span><span class="p">[(</span><span class="n">BYTE</span><span class="p">)</span> <span class="n">c</span>     <span class="p">]</span><span class="o">++</span><span class="p">;</span>
    <span class="n">Counting2</span><span class="p">[(</span><span class="n">BYTE</span><span class="p">)(</span><span class="n">c</span><span class="o">&gt;&gt;</span><span class="mi">8</span><span class="p">)</span> <span class="p">]</span><span class="o">++</span><span class="p">;</span>
    <span class="n">Counting3</span><span class="p">[(</span><span class="n">BYTE</span><span class="p">)(</span><span class="n">c</span><span class="o">&gt;&gt;</span><span class="mi">16</span><span class="p">)]</span><span class="o">++</span><span class="p">;</span>
    <span class="n">Counting4</span><span class="p">[</span>       <span class="n">c</span><span class="o">&gt;&gt;</span><span class="mi">24</span> <span class="p">]</span><span class="o">++</span><span class="p">;</span>
    <span class="n">c</span> <span class="o">=</span> <span class="n">cached</span><span class="p">;</span> <span class="n">cached</span> <span class="o">=</span> <span class="n">MEM_read32</span><span class="p">(</span><span class="n">ip</span><span class="p">);</span> <span class="n">ip</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
    <span class="n">Counting1</span><span class="p">[(</span><span class="n">BYTE</span><span class="p">)</span> <span class="n">c</span>     <span class="p">]</span><span class="o">++</span><span class="p">;</span>
    <span class="n">Counting2</span><span class="p">[(</span><span class="n">BYTE</span><span class="p">)(</span><span class="n">c</span><span class="o">&gt;&gt;</span><span class="mi">8</span><span class="p">)</span> <span class="p">]</span><span class="o">++</span><span class="p">;</span>
    <span class="n">Counting3</span><span class="p">[(</span><span class="n">BYTE</span><span class="p">)(</span><span class="n">c</span><span class="o">&gt;&gt;</span><span class="mi">16</span><span class="p">)]</span><span class="o">++</span><span class="p">;</span>
    <span class="n">Counting4</span><span class="p">[</span>       <span class="n">c</span><span class="o">&gt;&gt;</span><span class="mi">24</span> <span class="p">]</span><span class="o">++</span><span class="p">;</span>
    <span class="n">c</span> <span class="o">=</span> <span class="n">cached</span><span class="p">;</span> <span class="n">cached</span> <span class="o">=</span> <span class="n">MEM_read32</span><span class="p">(</span><span class="n">ip</span><span class="p">);</span> <span class="n">ip</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
    <span class="n">Counting1</span><span class="p">[(</span><span class="n">BYTE</span><span class="p">)</span> <span class="n">c</span>     <span class="p">]</span><span class="o">++</span><span class="p">;</span>
    <span class="n">Counting2</span><span class="p">[(</span><span class="n">BYTE</span><span class="p">)(</span><span class="n">c</span><span class="o">&gt;&gt;</span><span class="mi">8</span><span class="p">)</span> <span class="p">]</span><span class="o">++</span><span class="p">;</span>
    <span class="n">Counting3</span><span class="p">[(</span><span class="n">BYTE</span><span class="p">)(</span><span class="n">c</span><span class="o">&gt;&gt;</span><span class="mi">16</span><span class="p">)]</span><span class="o">++</span><span class="p">;</span>
    <span class="n">Counting4</span><span class="p">[</span>       <span class="n">c</span><span class="o">&gt;&gt;</span><span class="mi">24</span> <span class="p">]</span><span class="o">++</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>La figure ci-dessus est extraite de l’implémentation de la construction d’un
histogramme dans la bibliothèque <em>zstd</em>. Il peut sembler étrange de couper un
compteur en 4 parties et d’en faire la somme plus tard. Surtout sur un seul
thread, s’il y avait eu une strategie multithreadé on aurait pensé à un
<em>diviser pour mieux rêgner</em>, ou dans ce cas précis <em>pour rêgner plus vite</em>. En
réalité, c’est exactement le but recherché. Un processeur <em>OOO</em> peut
potentiellement exécuter simultanément les opérations suivantes : la lecture de
la mémoire à l’adresse <em>ip</em>, les affectations des variables <em>c</em> en cache, et les
accès aux différents tableaux.</p>

<!-- Apres relecture d'Yvan
    Je ne sais pas comment préciser que le CPU attend un temps considéré comme
    raisonnable, genre 100 clock iterations pour verifier les accès atomiques
    parallèles et les réorganiser.
-->

<!-- Apres relecture d'Yvan -->
<p>Parmi les différents ordonnancements possibles, celui qui contraint le plus la
sémantique d’un programme est <code class="language-plaintext highlighter-rouge">SeqCst</code> (Séquentiellement Consistant). Chaque
paire d’opérations atomiques <code class="language-plaintext highlighter-rouge">SeqCst</code> a le même comportement qu’une paire
<code class="language-plaintext highlighter-rouge">ACQUIRE-RELEASE</code>, en plus d’une caractéristique fondamentale : une série
chronologique <em>S</em> des événements de lectures et d’écritures est visible par
tous les threads du programme. Dans la conception d’un algorithme performant,
la construction de <em>S</em> par le processeur peut être un overhead à prendre en
compte. toutefois, il peut être indispensable pour résoudre plusieurs
problématiques, notamment si notre programme est constitué de plusieurs threads
de lecture et d’écriture.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">x</span> <span class="o">=</span> <span class="k">false</span>
<span class="k">let</span> <span class="n">y</span> <span class="o">=</span> <span class="k">false</span>
<span class="k">let</span> <span class="n">z</span> <span class="o">=</span> <span class="mi">0</span>

<span class="nf">write_x</span><span class="p">():</span>
    <span class="n">x</span><span class="nf">.store</span><span class="p">(</span><span class="k">true</span><span class="p">)</span>

<span class="nf">write_y</span><span class="p">():</span>
    <span class="n">y</span><span class="nf">.store</span><span class="p">(</span><span class="k">true</span><span class="p">)</span>

<span class="nf">read_x_then_y</span><span class="p">():</span>
    <span class="k">while</span> <span class="o">!</span><span class="n">x</span><span class="nf">.load</span><span class="p">()</span> <span class="p">{};</span>
    <span class="k">if</span> <span class="n">y</span><span class="nf">.load</span><span class="p">():</span>
        <span class="n">z</span><span class="nf">.fetch_add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

<span class="nf">read_y_then_x</span><span class="p">():</span>
    <span class="k">while</span> <span class="o">!</span><span class="n">y</span><span class="nf">.load</span><span class="p">()</span> <span class="p">{};</span>
    <span class="k">if</span> <span class="n">x</span><span class="nf">.load</span><span class="p">():</span>
        <span class="n">z</span><span class="nf">.fetch_add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

<span class="nf">main</span><span class="p">():</span>
    <span class="k">let</span> <span class="n">th1</span> <span class="o">=</span> <span class="nf">spawn</span><span class="p">(</span><span class="n">write_x</span><span class="p">)</span>
    <span class="k">let</span> <span class="n">th2</span> <span class="o">=</span> <span class="nf">spawn</span><span class="p">(</span><span class="n">write_y</span><span class="p">)</span>
    <span class="k">let</span> <span class="n">th3</span> <span class="o">=</span> <span class="nf">spawn</span><span class="p">(</span><span class="n">read_x_then_y</span><span class="p">)</span>
    <span class="k">let</span> <span class="n">th4</span> <span class="o">=</span> <span class="nf">spawn</span><span class="p">(</span><span class="n">read_y_then_x</span><span class="p">)</span>
    <span class="nf">join</span><span class="p">(</span><span class="n">th1</span><span class="p">,</span> <span class="n">th2</span><span class="p">,</span> <span class="n">th3</span><span class="p">,</span> <span class="n">th4</span><span class="p">)</span>
    <span class="nf">assert</span><span class="p">(</span><span class="n">z</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="c1">// Peut rater</span>
</code></pre></div></div>

<p>Le pseudocode ci-dessus est un extrait de la documentation des ordonnancements
mémoires en c++. Il est probable qu’en tant que lecteur, vous n’ayez pas prêté
suffisamment d’attention à la phrase <i>“D’autres threads peuvent avoir une
vision chronologique différente des événements”</i>, lors de la présentation de
<code class="language-plaintext highlighter-rouge">ACQUIRE</code>. Ce manque d’attention est naturel et devrait être pris en compte par
celui ou celle qui formule une explication, en répétant par exemple. Donc,
arrêtons-nous sur cet algorithme.</p>

<p>Si j’utilisais par défaut l’ordre défini par <code class="language-plaintext highlighter-rouge">ACQUIRE-RELEASE</code>, les threads
<code class="language-plaintext highlighter-rouge">th3</code> et <code class="language-plaintext highlighter-rouge">th4</code> auraient potentiellement une vision différente de l’historique
des accès aux variables <code class="language-plaintext highlighter-rouge">x</code> et <code class="language-plaintext highlighter-rouge">y</code>, car elles ont étés modifiées par deux
threads différents. Utiliser une contrainte plus élevée <code class="language-plaintext highlighter-rouge">SeqCst</code> qui partage la
chronologie <em>S</em> des accès à la mémoire à travers le processeur permet donc de
résoudre les <em>data races</em> entre ces threads. Autrement dit, si pour <code class="language-plaintext highlighter-rouge">th3</code>
l’écriture de <code class="language-plaintext highlighter-rouge">x</code> est <em>séquentiellement avant</em> l’écriture de <code class="language-plaintext highlighter-rouge">y</code> alors pour
<code class="language-plaintext highlighter-rouge">th4</code> aussi.</p>

<p>Notez également que la garantie d’une contrainte d’ordonnancement quelle
qu’elle soit est toujours rompue lorsqu’un accès à la zone mémoire est
non-atomique ou possède des contraintes moins élevées. On en déduit donc qu’une
lecture <code class="language-plaintext highlighter-rouge">SeqCst</code> N aura pour résultat soit la dernière valeur écrite par une
modification <code class="language-plaintext highlighter-rouge">SeqCst</code> M dans <em>S</em>, soit toute autre valeur écrite par une
modification non-atomique, <code class="language-plaintext highlighter-rouge">RELEASE</code> ou <code class="language-plaintext highlighter-rouge">RELAXED</code> effectuée entre M et N qui
n’est pas dans <em>S</em>.</p>

<p align="center">
  <img width="400" src="/assets/img/state_machine_1/seqcst_atomic_order.png" />
</p>

<!-- -->

<p>Une variable peut être atomique dans le cas où elle est assez petite. Elle est
généralement d’un type primitif, un pointeur, sur 32 ou 64 bits. On peut lui
donner des ordonnancements d’accès en lecture et écriture de manière à ce que
différents threads ne tombent pas dans des <em>data races</em>. Et dans tout les cas,
il est préférable, si on utilise ces variables, de donner l’ordonnancement
<code class="language-plaintext highlighter-rouge">SeqCst</code> qui est la contrainte la plus élevée avant de tenter autre chose. En
ce qui concerne les conteneurs (set, hashmap, etc) une opération atomique est
bien plus complexe à réaliser et nécessite parfois des algorithmes de consensus
avancés.</p>

<h2 id="chapitre-5---atomique">Chapitre 5 - Atomique</h2>

<p>Il existe certains cas où tout se déroule au mieux, même sans préciser
l’atomicité dans le code, ou avec des ordonnancements plus faibles que
<code class="language-plaintext highlighter-rouge">SeqCst</code>. Notamment sur des processeurs <code class="language-plaintext highlighter-rouge">x86</code>. Cela devient intéressant de
savoir pourquoi et comment le mécanisme se traduit en instructions.</p>

<p>Pour observer les instructions qu’un processeur Intel peut comprendre, on peut
commencer par écrire avec un langage haut niveau les différents concepts
atomiques que la plupart des langages nous permettent d’utiliser. Je vais donc
écrire un programme de différentes façons, avec des méthodes plus ou moins
validées par la communauté des développeurs. Ce programme consiste
principalement en deux threads. L’un produit, l’autre consomme. Le producteur
incrémente une variable jusqu’à ce qu’elle soit égale à 5, l’autre lit tant que
la même variable ne vaut pas 5. Après quoi, le programme s’arrête.</p>

<p>Je vous épargnerai les déclarations de bibliothèques et la fonction de
démarrage. Préférant me concentrer sur les routines des différents threads.</p>

<p>La première version utilise des <em>mutexes</em>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="o">*</span><span class="nf">producer_thread</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">counter</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">c</span> <span class="o">!=</span> <span class="mi">5</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">pthread_mutex_lock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">COUNTER_MUTEX</span><span class="p">);</span>
        <span class="o">*</span><span class="p">(</span><span class="kt">int</span> <span class="o">*</span><span class="p">)</span><span class="n">counter</span> <span class="o">=</span> <span class="o">++</span><span class="n">c</span><span class="p">;</span>
        <span class="n">pthread_mutex_unlock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">COUNTER_MUTEX</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="o">*</span><span class="nf">consumer_thread</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">counter</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">c</span> <span class="o">!=</span> <span class="mi">5</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">pthread_mutex_lock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">COUNTER_MUTEX</span><span class="p">);</span>
        <span class="n">c</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">int</span> <span class="o">*</span><span class="p">)</span><span class="n">counter</span><span class="p">;</span>
        <span class="n">pthread_mutex_unlock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">COUNTER_MUTEX</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Dans cette version, mon postulat est que l’invocation d’un verrou autour de ma
variable est inutilement coûteuse. En plus, je dois gérer une variable globale
pour en contrôler l’accès. Cette méthode est particulièrement utilisée lorsque le
type de <code class="language-plaintext highlighter-rouge">counter</code> n’est pas primitif. Si c’était une structure ou un tableau,
cette méthode serait acceptable.</p>

<p>À noter qu’ici, il serait simple de modifier le programme de façon à ce qu’on
puisse avoir plusieurs producteurs sans créer de comportement indéfini. Il
suffirait d’ajouter dans la boucle du producteur un test de la variable pour
voir si elle est déjà égale à 5. Le cas échéant, on retourne une erreur ou l’on
sort simplement de la fonction.</p>

<p>Voilà la deuxième version:</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="o">*</span><span class="nf">producer_thread</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">counter</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="n">atomic_fetch_add_explicit</span><span class="p">(</span>
        <span class="p">(</span><span class="n">atomic_int</span> <span class="o">*</span><span class="p">)</span><span class="n">counter</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span>
        <span class="n">__ATOMIC_RELEASE</span><span class="p">);</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">c</span> <span class="o">!=</span> <span class="mi">4</span><span class="p">)</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">atomic_fetch_add_explicit</span><span class="p">(</span>
            <span class="p">(</span><span class="n">atomic_int</span> <span class="o">*</span><span class="p">)</span><span class="n">counter</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span>
            <span class="n">__ATOMIC_RELEASE</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="o">*</span><span class="nf">consumer_thread</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">counter</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="n">atomic_load_explicit</span><span class="p">(</span>
        <span class="p">(</span><span class="n">atomic_int</span> <span class="o">*</span><span class="p">)</span><span class="n">counter</span><span class="p">,</span>
        <span class="n">__ATOMIC_ACQUIRE</span><span class="p">);</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">c</span> <span class="o">!=</span> <span class="mi">5</span><span class="p">)</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">atomic_load_explicit</span><span class="p">(</span>
            <span class="p">(</span><span class="n">atomic_int</span> <span class="o">*</span><span class="p">)</span><span class="n">counter</span><span class="p">,</span>
            <span class="n">__ATOMIC_ACQUIRE</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Cette fois-ci, plus de mutex ni de verrouillage. On utilise une opération
atomique basique <code class="language-plaintext highlighter-rouge">fetch_add</code> qui va, sans surprise, incrémenter la valeur du
compteur. <code class="language-plaintext highlighter-rouge">fetch_add</code> produit sur ma machine la ligne instruction <code>lock
xaddl %edx, (%rax)`</code>. C’est une opération d’addition entre <code class="language-plaintext highlighter-rouge">edx</code> et
<code class="language-plaintext highlighter-rouge">rax</code>, avec le préfixe <code class="language-plaintext highlighter-rouge">lock</code>. Ce préfixe permet entre autres de préciser au
processeur que la valeur de la cible ne peut ni être changée ni lue pendant
l’incrémentation. Utiliser cette fonction est considéré comme <code class="language-plaintext highlighter-rouge">wait-free</code> si
vous êtes familier avec les types d’algorithmes multithreadés.</p>

<p>La version ci-dessus nous empêche d’avoir plusieurs producteurs. Effectivement,
on risque d’avoir une variable temporaire <code class="language-plaintext highlighter-rouge">c</code> qui ne soit plus la bonne,
cependant, on continue à incrémenter le compteur. C’est ce qu’on appel un <em>data
race</em>. Ce risque de <em>data race</em> est à prendre en compte. Même si dans ce cas,
tout va bien, ajouter un ou plusieurs producteurs en parallèle pourrait créer
des boucles infinies.</p>

<p>La dernière version ci-dessous n’utilise même plus d’opérations atomiques et
fonctionne parfaitement. Cette version ne marche que parce que les instructions
<code class="language-plaintext highlighter-rouge">mov</code> ont le même comportement entre eux que des variables atomiques avec
les ordonnancements <code class="language-plaintext highlighter-rouge">ACQUIRE-RELEASE</code> sur un processeur Intel. De plus, le contexte
n’a que deux threads.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="o">*</span><span class="nf">producer_thread</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">counter</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">c</span> <span class="o">!=</span> <span class="mi">5</span><span class="p">)</span>
        <span class="o">*</span><span class="p">(</span><span class="kt">int</span> <span class="o">*</span><span class="p">)</span><span class="n">counter</span> <span class="o">=</span> <span class="o">++</span><span class="n">c</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="o">*</span><span class="nf">consumer_thread</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">counter</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">while</span> <span class="p">(</span><span class="n">c</span> <span class="o">!=</span> <span class="mi">5</span><span class="p">)</span>
        <span class="n">c</span> <span class="o">=</span> <span class="o">*</span><span class="p">(</span><span class="kt">int</span> <span class="o">*</span><span class="p">)</span><span class="n">counter</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>En pratique, que l’on utilise <code class="language-plaintext highlighter-rouge">RELAXED</code> ou <code class="language-plaintext highlighter-rouge">ACQUIRE-RELEASE</code> ne change rien.
Cela dit, utiliser l’ordonnancement par défaut, <code class="language-plaintext highlighter-rouge">SeqCst</code>, reste la meilleure
des pratiques. Ne vous risquez pas trop à changer cette règle pour des bouts de
chandelle de performance.</p>

<p>Cette version ne permet pas du tout d’avoir de multiples producteurs. On
pourrait la modifier légèrement en utilisant la fonction atomique
<code class="language-plaintext highlighter-rouge">compare_and_swap</code> dans la boucle du producteur. Cette fonction permet de
vérifier si la valeur de <code class="language-plaintext highlighter-rouge">c</code> est bien celle qui se trouve dans le compteur au
moment de l’échange. Et si ce n’est pas le cas, on récupère sa valeur actuelle,
et on essaie à nouveau si besoin. <code class="language-plaintext highlighter-rouge">compare_and_swap</code> est l’élément qui manquait
aussi à la deuxième version. Cependant, si l’utilisation de <code class="language-plaintext highlighter-rouge">fetch_add</code> est
<em>wait-free</em>, l’équivalent sans les <em>data race</em> avec <code class="language-plaintext highlighter-rouge">compare_and_swap</code> est
<em>lock-free</em>. La figure ci-dessous pourra vous donner un aperçu concis des
niveaux qu’un algorithme multithreadé peut avoir.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">atomic_int</span> <span class="n">i</span><span class="p">;</span>

<span class="c1">// obstruction-free</span>
<span class="n">lock</span><span class="p">(</span><span class="n">MUTEX</span><span class="p">);</span>
<span class="n">i</span><span class="o">++</span><span class="p">;</span>
<span class="n">unlock</span><span class="p">(</span><span class="n">MUTEX</span><span class="p">);</span>

<span class="c1">// lock-free</span>
<span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="n">load</span><span class="p">(</span><span class="o">&amp;</span><span class="n">i</span><span class="p">);</span>
<span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">cas</span><span class="p">(</span><span class="o">&amp;</span><span class="n">i</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="n">c</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span>
    <span class="n">c</span> <span class="o">=</span> <span class="n">load</span><span class="p">(</span><span class="o">&amp;</span><span class="n">i</span><span class="p">));</span>

<span class="c1">// wait-free</span>
<span class="n">atomic_fetch_add</span><span class="p">(</span><span class="o">&amp;</span><span class="n">i</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
</code></pre></div></div>

<!-- Ajout après relecture Yvan -->
<blockquote>
  <p>Cette figure présente plusieurs classes d’algorithmes. Précisons que ces
exemples n’ont de sens que dans des systèmes concurrents, où ils peuvent
interférer simultanément avec d’autres composants ayant des effets sur des
éléments communs. Les noms ou les caractéristiques associées à ces classes sont
organisés selon l’ordre suivant: un algorithme <em>wait-free</em> est également
<em>lock-free</em>, et un algorithme <em>lock-free</em> est également <em>obstruction-free</em>.
Avant de détailler ces termes afin d’en comprendre leur signification, il est
utile de souligner un point important. En effet, le fait de nommer une routine
<em>wait-free</em>, <em>lock-free</em> ou <em>obstruction-free</em> indique le comportement garanti
par celle-ci. Cependant, chaque catégorie présente des faiblesses absentes dans
les catégories supérieures. Par exemple, un algorithme <em>obstruction-free</em> peut
avoir des inconvénients alors qu’un algorithme <em>wait-free</em> n’en aura pas. En
outre, on entend ici qu’un tel algorithme pourra interferer avec au moins un
homologue de lui-même sur des threads parallèles.</p>

  <p>À présent que le contexte d’utilisation de ces termes est claire, nous pouvons
les définir sans ambiguïtés. Commençons par la classe d’algorithme
<em>obstruction-free</em>, cette classe, donc, décrit une routine qui garantit que :
si elle est seule à s’éxecuter sur son système durant son intervalle d’action,
alors elle pourra faire avancer son état sans être interrompue.  Cependant, si
d’autres routines s’exécutent en parallèle, une routine de cette classe peut
être bloquée soit par l’utilisation d’un verrou, soit par une stratégie de
veille particulière. La durée de ce blocage, bien qu’habituellement brève, est
indéterminée. Finalement, le plus grand défaut de ce type de routine est son
incapacité à faire avancer son propre état lors d’une interférence.</p>

  <p>La classe supérieure <em>lock-free</em> est moins contraignante. Elle est bien plus
préférable dans la majeure partie des cas, bien qu’elle ne se prête pas à tous
les scénarios. Elle garantit pour une routine que : si elle s’éxecute en
parallèle d’une copie d’elle-même ou d’autres parties de l’algorithme, alors
parmi les différentes exécutions en cours sur le système (elle comprise) une
pourra terminer lors d’un certain nombre de ses étapes. Elle tentera toujours
de faire avancer son propre état, quitte à recommencer du début. Contrairement
à un algorithme <em>obstruction-free</em>, elle est potentiellement capable d’agir sur
elle-même. C’est-à-dire qu’elle peut, dans une situation d’attente, s’arrêter,
s’annuler, continuer ou recommencer, sans intervention extérieure.</p>

  <p>Les algorithmes de la classe <em>“wait-free”</em> ne se préoccupent pas des autres
threads. Les conflits d’accès simultanés sont gérés à un niveau plus bas par le
processeur. Par exemple, grâce à une instruction atomique <em>“read-and-write”</em>
qui protège une variable pendant la lecture, la mise à jour et l’écriture telle
que <code class="language-plaintext highlighter-rouge">fetch_add</code>. De même, les instructions <code class="language-plaintext highlighter-rouge">swap</code> ou <code class="language-plaintext highlighter-rouge">store</code> modifient une
variable sans se soucier de conditions particulières. Contrairement à une
classe d’algorithmes <em>“lock-free”</em>, qui doit attendre pour réaliser des effets
de vérifier si des accès concurents ont eu lieu, et le cas échéant recommencer,
une routine <em>“wait-free”</em> se termine sans tenir compte des autres threads
concurrents. En d’autres termes, si elle est exécutée en parallèle avec une
copie d’elle-même ou d’autres parties de l’algorithme qui partage la même
structure de données, elle se terminera avec succès. 
<!----></p>
</blockquote>

<p>Revenons aux ordonnancements. Spécifier un ordre dans lequel les threads vont
accéder à une variable et les contraintes sur un seul thread est possible dans
quasiment tout les langages permettant la parallélisation des exécutions. En
Go, il n’est possible d’utiliser que l’ordonnancement <code class="language-plaintext highlighter-rouge">SeqCst</code>. En Rust, les
types atomiques sont identiques au C/C++, bien qu’entre ces langages, certains
choisissent de déprecier des méthodes et d’autre non. L’idée cependant est là.
Avec l’atomicité, on peut par exemple simuler ce que ferait un mutex protegeant
une variable. Voici l’exemple le plus classique que vous pourrez trouver à
propos des opérations de lectures et écritures atomiques.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">thread_a</span><span class="p">(</span><span class="n">atomic_bool</span><span class="p">:</span> <span class="nb">Arc</span><span class="o">&lt;</span><span class="n">AtomicBool</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">val</span><span class="p">:</span> <span class="nb">Arc</span><span class="o">&lt;</span><span class="n">AtomicU32</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">val</span><span class="nf">.store</span><span class="p">(</span><span class="mi">42</span><span class="p">,</span> <span class="nn">Ordering</span><span class="p">::</span><span class="n">Relaxed</span><span class="p">);</span>
    <span class="n">atomic_bool</span><span class="nf">.store</span><span class="p">(</span><span class="k">true</span><span class="p">,</span> <span class="nn">Ordering</span><span class="p">::</span><span class="n">Release</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">thread_b</span><span class="p">(</span><span class="n">atomic_bool</span><span class="p">:</span> <span class="nb">Arc</span><span class="o">&lt;</span><span class="n">AtomicBool</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">val</span><span class="p">:</span> <span class="nb">Arc</span><span class="o">&lt;</span><span class="n">AtomicU32</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">b</span> <span class="o">=</span> <span class="n">atomic_bool</span><span class="nf">.load</span><span class="p">(</span><span class="nn">Ordering</span><span class="p">::</span><span class="n">Acquire</span><span class="p">);</span>
    <span class="k">while</span> <span class="o">!</span><span class="n">b</span> <span class="p">{</span>
        <span class="n">b</span> <span class="o">=</span> <span class="n">atomic_bool</span><span class="nf">.load</span><span class="p">(</span><span class="nn">Ordering</span><span class="p">::</span><span class="n">Acquire</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">let</span> <span class="n">v</span> <span class="o">=</span> <span class="n">val</span><span class="nf">.load</span><span class="p">(</span><span class="nn">Ordering</span><span class="p">::</span><span class="n">Relaxed</span><span class="p">);</span>
    <span class="nd">assert!</span><span class="p">(</span><span class="n">b</span><span class="p">);</span>
    <span class="nd">assert_eq!</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="mi">42</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<div class="figure-title">Synchronisation, spinlock</div>

<p>La figure ci-dessus est un exemple de synchronisation. De la même manière qu’un
garde (mutex verrouillé) relaché dans un thread A puis acquis dans un thread B,
ce qui a été stocké par le thread A est visible par le thread B. Dans la mesure
où la modification de <code class="language-plaintext highlighter-rouge">atomic_bool</code> est garantie d’être faite après celle de
<code class="language-plaintext highlighter-rouge">val</code> dans A, et à l’inverse, la lecture de <code class="language-plaintext highlighter-rouge">atomic_bool</code> est garantie d’être
faite avant celle de <code class="language-plaintext highlighter-rouge">val</code> dans B.</p>

<p>Une écriture avec un ordre atomique <code class="language-plaintext highlighter-rouge">RELEASE</code> implique qu’aucune écriture ou
lecture dans le même thread ne peut être réorganiser par le processeur après le
stoquage, que l’opération soit atomique ou non-atomique. Autrement dit, ce qui
est écrit ou lu avant sera vraiment écrit ou lu avant. De plus, toute écriture
dans une variable devient visible par tous les autres threads voulant lire avec
un ordre atomique <code class="language-plaintext highlighter-rouge">ACQUIRE</code>. Pour résumer simplement, <code class="language-plaintext highlighter-rouge">val</code> est comme protégée
par un mutex. Cette façon d’attendre activement l’accès à une ressource
s’appelle un <em>spinlock</em>. Très utile dans certains cas, et bien trop gourmand en
temps de CPU dans d’autres.</p>

<p>Sans l’utilisation de lecture et écriture atomique, un programme multithreadé
de la sorte se risquerait à un comportement indéfini pour quelques processeurs.
Et d’ailleurs le compilateur de Rust ne permettrait pas d’écrire le spinlock
dans la figure précédente sans l’utilisation du mot-clef <code class="language-plaintext highlighter-rouge">unsafe</code>.</p>

<h2 id="chapitre-6---létat-dans-lequel-je-suis">Chapitre 6 - L’état dans lequel je suis</h2>

<p>Une machine à états conserve toujours au moins son état actuel. Que cet état
soit représenté par une variable, une pile, ou simplement par la position de
son l’exécution sur la stack.</p>

<p>Pour Reagir (ma bibliothèque) comme pour React, les états sont des variables
qu’on récupère à un moment de l’exécution. Dans l’implémentation de Reagir,
l’état ne peut pas se trouver sur la pile. Si c’était le cas, on ne pourrait
jamais dépiler les exécutions et le programme grossirait en mémoire
continuellement. Les états de la bibliothèque Reagir sont donc quelque part sur
le tas, ou globaux. Par défaut, on les considère constants ou statiques.</p>

<p>À l’écriture d’un programme, ce n’est pas toujours pratique d’avoir des états
constants et immutables. Dans la plupart des exemples trouvé avec React, l’état
est modifié au fur et à mesure. Personnellement, j’aime aussi considérer l’état
comme une base avec laquelle je profile l’exécution, puis j’en tire l’état
suivant si besoin. Contrairement au Rust, C me donne la liberté de créer des
variables statiques mutables sans protections, ce qui rend d’ailleurs ce vieux
langage non <em>memory safe</em>. En contre partie, ça me permet de ne pas à avoir à
allouer de mémoire dynamiquement, et surtout, d’avoir un code simple.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="o">*</span><span class="nf">make_init_state</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">static</span> <span class="kt">char</span> <span class="n">val</span><span class="p">[</span><span class="mi">300</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="sc">'\0'</span><span class="p">};</span>
    <span class="k">static</span> <span class="k">struct</span> <span class="n">State</span> <span class="n">st</span> <span class="o">=</span> <span class="p">{</span>
        <span class="n">val</span><span class="p">,</span>
        <span class="mi">0</span><span class="p">,</span>
        <span class="n">zero</span><span class="p">,</span>
        <span class="n">first_print</span><span class="p">,</span>
        <span class="mi">0</span><span class="p">,</span>
    <span class="p">};</span>
    <span class="k">return</span> <span class="o">&amp;</span><span class="n">st</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">state_machine</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">Reaction</span> <span class="o">*</span><span class="n">re</span> <span class="o">=</span> <span class="n">use_state</span><span class="p">(</span><span class="n">make_init_state</span><span class="p">);</span>
    <span class="k">struct</span> <span class="n">State</span> <span class="o">*</span><span class="n">st</span> <span class="o">=</span> <span class="n">re</span><span class="o">-&gt;</span><span class="n">state</span><span class="p">;</span> <span class="c1">// Récupération de l'état</span>
    <span class="c1">// ...</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Un des choix arbitraires pris ici, est l’argument qu’on donne à la fonction
<code class="language-plaintext highlighter-rouge">use_state</code>. Avec React, on donne directement une référence vers l’état
initial, puis on utilise la référence du scope pour le reste de l’exécution. Ce
n’est pas très pratique pour un modèle de mémoire sans <em>garbage collector</em>. Le
choix de passer une fonction d’initialisation, malgré les contraintes du
langage, reste arbitraire. J’imagine sans mal qu’il y ai de nombreuses
implémentations alternatives. Certaines me viennent à l’esprit en écrivant ces
lignes. Bien que celle-ci ne constitue pas un défaut majeur.</p>

<p>Vous avez peut-être remarqué une autre différence avec React qu’implique cette
implémentation. En utilisant le framework javascript, appeler la méthode
<code class="language-plaintext highlighter-rouge">dispatch</code> (qui permet de mettre à jour l’état) avec le même objet ne
re-demande pas l’exécution du composant, même si cet objet a été modifié. Dans
le cas ci-dessus, si on gardait la même logique le pointeur pour l’état initial
ne pourrait pas être celui des états suivants. Donc ma bibliothèque est forcée
d’accepter tout appel à <code class="language-plaintext highlighter-rouge">dispatch</code> sans vérifier la consistence ou l’égalité
des états.</p>

<p>Je recommande tout de même de ne pas réutiliser l’état précédent dans la
fonction de dispatch sans maîtriser ce que vous faites. Le mieux serait de
pouvoir utiliser une variable statique par état. La raison pour laquelle il
n’est pas conseillé de garder l’état précédent, est qu’il peut être modifié par
d’autres parties de l’application avant que la fonction de dispatch n’ait été
exécutée ou pendant son transit dans la file d’évènements. Dans ce cas, des
<em>data races</em> peuvent entraîner des erreurs difficiles à déboguer.</p>

<p>Quelques chapitres au-dessus, on a vu comment des fonctions de réduction sont
enfilées. J’ai précisé ensuite que ces fonctions sont exécutées
séquentiellement et leur impacte.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">Reagir</span> <span class="o">*</span><span class="n">re</span> <span class="o">=</span> <span class="n">new_reagir</span><span class="p">(</span><span class="n">pthread_self</span><span class="p">());</span>                 <span class="c1">// L1</span>
<span class="k">while</span> <span class="p">(</span><span class="n">state_machine</span><span class="p">())</span>                                         <span class="c1">// L2</span>
<span class="p">{</span>
    <span class="n">re</span><span class="o">-&gt;</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>                                                  <span class="c1">// L3</span>
    <span class="k">struct</span> <span class="n">Entry</span> <span class="n">e</span> <span class="o">=</span> <span class="n">receive_state</span><span class="p">(</span><span class="n">re</span><span class="p">);</span>                         <span class="c1">// L4</span>
    <span class="kt">void</span> <span class="o">*</span><span class="n">new_state</span> <span class="o">=</span> <span class="n">e</span><span class="p">.</span><span class="n">rea</span><span class="o">-&gt;</span><span class="n">reducer</span><span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">rea</span><span class="o">-&gt;</span><span class="n">pub</span><span class="p">.</span><span class="n">state</span><span class="p">,</span> <span class="n">e</span><span class="p">.</span><span class="n">arg</span><span class="p">);</span>  <span class="c1">// L5</span>
    <span class="n">opt</span><span class="p">.</span><span class="n">on_state_change</span><span class="p">(</span><span class="o">&amp;</span><span class="n">e</span><span class="p">.</span><span class="n">rea</span><span class="o">-&gt;</span><span class="n">pub</span><span class="p">.</span><span class="n">state</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">new_state</span><span class="p">);</span>         <span class="c1">// L6</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Dans l’implémentation de la boucle d’exécution, vous remarquerez qu’il n’y a
aucun nettoyage des états précédents. Dans un langage qui n’est pas <em>garbage
collecté</em>, c’est un peu problématique. À la place, la bibliothèque appelle une
fonction paramétrable, qui permet pour nous de résoudre plusieurs problèmes,
dont deux que je souhaite vous exposer.</p>

<p>Premier problème : que se passe-t-il si je souhaite utiliser des états alloués
sur ma <em>heap</em> ? Si c’est le cas, il faut trouver le juste moment où on possède
encore l’adresse de l’état précédent afin de libérer cet espace mémoire. Une
des possibilités qui n’embête pas trop l’utilisateur de la bibliothèque est
celle-ci: <code class="language-plaintext highlighter-rouge">on_state_change</code> s’occupera de nettoyer. C’est simple et efficace, à
la création de la machine à états, on donne en paramètre une fonction.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">on_change_with_free</span><span class="p">(</span><span class="kt">void</span> <span class="o">**</span><span class="n">dst</span><span class="p">,</span> <span class="kt">void</span> <span class="o">**</span><span class="n">src</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">free</span><span class="p">(</span><span class="o">*</span><span class="n">dst</span><span class="p">);</span>
    <span class="o">*</span><span class="n">dst</span> <span class="o">=</span> <span class="o">*</span><span class="n">src</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">main</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">Opt</span> <span class="n">opt</span> <span class="o">=</span> <span class="p">{</span><span class="n">on_change_with_free</span><span class="p">};</span>
    <span class="n">create</span><span class="p">(</span><span class="n">state_machine</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">opt</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>La proposition précédente fonctionne parfaitement dans un contexte synchrone.
Si, à tout moment de l’exécution, plusieurs threads pouvaient utiliser ces
états créés, dans ce cas, ce bout de code est très très critique. Cependant, il
existe des situations où les exécutions seront toujours concurrentes, jamais
parallèles, et où ce code fonctionne en l’état. Mais cela n’est pas très
générique, ce qui nous amène au second problème.</p>

<p>Second problème : imaginons que pendant la réception d’une nouvelle information
la machine à états passe de l’état “A” à “B”. L’exécution vient de passer la ligne
L5 (voir la figure de la boucle) et est en train d’entrer dans la fonction de
réduction. Si un autre thread modifie “A” à ce moment-là, la fonction de
réduction et cet autre thread auront un <em>data race</em>. Au mieux, l’état ne
passera pas à B, mais la fonction de réduction ne peut pas avoir de
comportement défini.</p>

<p>Pour se protéger, la solution la moins évidente à réaliser, est de faire en
sorte que le programme soit au choix résilient ou qu’il y ait un consensus
entre les threads. L’utilisation de structures non-bloquantes, encore, permet
d’éviter des <em>data races</em>. La fonction de réduction pourrait tenter de
remplacer l’ancien état avec un <code class="language-plaintext highlighter-rouge">compare_and_swap</code> élaboré, et essayer de
nouveau tant que l’opération échoue. Dans ce cas, il faut aussi se protéger
contre des libérations de mémoire inattendues. L’accès à une structure, aussi
atomique soit-elle, ne protège pas contre l’apparition d’un pointeur nul comme
référence.</p>

<p>Une manière plus simple de se protéger est l’utilisation de verrous. En
combinant une fonction de réduction qui enclenche un verrou et la fonction de
nettoyage pour le relacher, on peut réussir à protéger l’état contre des
comportements indéfinis. Le verrou peut être contenu dans la machine à état.
Dans toutes les circonstances, il n’y a toujours qu’un état courant, donc
l’utilisation d’un verrou global est largement suffisante.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="o">*</span><span class="nf">locker</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">_</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">new_state</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">lock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">state_mutex</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">new_state</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">my_on_state_change</span><span class="p">(</span><span class="kt">void</span> <span class="o">**</span><span class="n">dst</span><span class="p">,</span> <span class="kt">void</span> <span class="o">**</span><span class="n">src</span><span class="p">)</span>
<span class="p">{</span>
    <span class="n">free</span><span class="p">(</span><span class="o">*</span><span class="n">dst</span><span class="p">);</span> <span class="c1">// dans le cas où j'utilise la heap.</span>
    <span class="o">*</span><span class="n">dst</span> <span class="o">=</span> <span class="o">*</span><span class="n">src</span><span class="p">;</span>
    <span class="n">unlock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">state_mutex</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">struct</span> <span class="n">Reagir</span><span class="o">*</span> <span class="nf">state_machine</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">struct</span> <span class="n">Reagir</span> <span class="o">*</span><span class="n">re</span> <span class="o">=</span> <span class="n">use_reducer</span><span class="p">(</span>
        <span class="n">locker</span><span class="p">,</span>
        <span class="n">initializer</span>
    <span class="p">);</span>
    <span class="k">return</span> <span class="n">re</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="chapitre-7---une-file-plus-rapide">Chapitre 7 - Une file plus rapide</h2>

<p>Admettons que la situation nous impose d’optimiser la lecture et l’écriture de
la file. Effectivement, la structure <em>mpsc</em> implique un goulot d’étranglement.
Admettons qu’utiliser un simple verrou sur la file de la machine à états ne
suffise pas car utiliser des <em>mutexes</em> coûte au CPU un temps trop précieux pour
nous.</p>

<p>Une file est une structure de données qui en théorie n’a pas de taille précise
et qui implémente au moins deux fonctions: <code class="language-plaintext highlighter-rouge">pop</code> et <code class="language-plaintext highlighter-rouge">push</code> (défiler et enfiler)
et dont les éléments qui entrent et sortent respectent l’ordre <em>FIFO</em>. Avant de
commencer à présenter différentes façons d’optimiser cette structure, regardons
ce que font ces deux routines lorsqu’elles sont synchrones.</p>

<p><em>Push</em>, par exemple va:</p>
<ol>
  <li>Créer un nouveau noeud.</li>
  <li>Trouver la fin de la file.</li>
  <li>Relier la fin de la file avec le nouveau noeud d’une quelconque manière.</li>
  <li>Modifier le pointeur de fin de file avec le nouveau noeud.</li>
</ol>

<p><em>Pop</em>:</p>
<ol>
  <li>Trouver la tête de la file.</li>
  <li>Trouver l’élément suivant.</li>
  <li>Échanger le pointeur de en tête de file avec l’élément suivant.</li>
  <li>Supprimer l’ancien noeud.</li>
</ol>

<p>Les pointeurs de tête et de fin sont initialisés avec un noeud vide qu’on
appellera des <code class="language-plaintext highlighter-rouge">dummies</code>, ils serviront essentiellement à combler le début et la
fin de la file et peuvent être, ou doivent être (selon l’implémentation), égaux
et occuper la même zone mémoire. Plus important, la plupart de ces opérations
sont invalides dans un contexte de partage de données entre plusieurs threads
parallèles.</p>

<!-- Ajout après relecture d'Yvan -->
<p>Avant de continuer ce chapitre, il semble nécessaire de savoir reconnaitre si
une structure de données, ou plus généralement un algorithme qui produira des
effets, est <em>thread-safe</em> ou non. Dans un système concurrent, composé de
plusieurs processus et incluant du parallélisme, j’appellerai <em>“thread-safe”</em>
un algorithme avec une sémantique synchrone qui gardera cette même sémantique
dans tout les scénarios possibles d’appels asynchrones. Parmi les effets
indésirables d’un tel algorithme, on peut identifier les désynchronisations,
les pertes de données, les fuites de mémoire et tout type de comportements
imprévisibles, à condition bien sûr que ces effets ne soient pas souhaités dans
la sémantique originale.</p>

<p>Toutefois, s’il est plus ou moins facile de montrer qu’un algorithme ne remplit
pas les conditions pour être <em>thread-safe</em> il est difficile de prouver le
contraire sans le matériel adapté. Heureusement, il existe quelques langages
spécifiques qui permettent de vérifier la conformité d’un algorithme par
rapport à ses spécifications. Cependant, excluant le fait que je ne les
maîtrise pas, il serait surérogatoire de les présenter ici.</p>

<!-- -->

<p align="center">
  <img width="400" src="/assets/img/state_machine_1/scenario_data_race_file_2.png" />
</p>

<p>La figure ci-dessus montre un des nombreux scénarios de désynchronisation qui
pourraient arriver. En fait, en utilisant cette structure non protégée, ça ne
se passera quasiment jamais bien. Si on reste dans des exécutions concurrentes,
dans des <em>green threads</em>, pourquoi pas. Mais en incluant du parallélisme, il y
a un fort risque de perte de données et de comportement indéfini. Dans ce cas,
la solution la plus évidente est d’ajouter un mutex autour de la file partagée.
Des solutions plus performantes entrent alors en scène.</p>

<!-- Modification des paragraphes après relecture Yvan -->
<p>L’étape suivante d’une structure de données <em>thread-safe</em>, après le grand
mutex, c’est le status <em>non-bloquant</em> ou <em>lock-free</em>. Quand on parle
d’algorithmes <em>lock-free</em>, on l’a vu, on veut dire que l’appel d’une routine
comme <em>Push</em> garantira que des appels parallèles à <em>Push</em> et <em>Pop</em> pourront se
terminer à une ou plusieurs étapes l’exécution. Autrement dit, on arrive à
s’organiser entre threads de façon à se partager la structure de données sans
se marcher sur les pieds. Précisons tout de même qu’on utilise l’expression <em>se
terminer</em> (sous-entendu avec succès) sans la suite logique <em>et avoir fait
effet</em>, car ce sont deux concepts distincts qu’on différencie entre
<em>parallélisation</em> et <em>linéarisabilité</em> que j’évoquerai plus tard. Je distingue
par la suite les termes <em>lock-free</em> et <em>non bloquant</em>, car il est possible
d’obtenir dans plusieurs cas des accès parallèles de lecture et écriture à une
même structure avec l’utilisation de mutexes.</p>

<p>Pour l’implémentation d’une file adaptée à divers systèmes de producteurs et
consommateurs, on peut utiliser une version synchrone de l’algorithme. Elle ne
sera pas <em>lock-free</em> mais non-bloquante. Elle ressemble à ce qu’on a vu
précédemment dans <code class="language-plaintext highlighter-rouge">send_state</code> et <code class="language-plaintext highlighter-rouge">receive_state</code>. Sauf qu’on différenciera le
mutex de tête de file et celui de fin de file. Un producteur et un consommateur
ne se bloqueront jamais l’un l’autre. Cependant, on utilise deux verrous, ce
qui signifie qu’on ne peut pas appeler cette structure <em>lock-free</em>. Ici, on
décrit un algorithme qui garantit qu’au moins un thread peut continuer à
s’exécuter pendant que d’autres threads sont bloqués. Un consommateur peut
s’exécuter même si un producteur bloque la file. Par contre, plusieurs
producteurs n’auront pas d’accès simultanés. Cette stratégie s’appelle
<em>“livelock-free”</em>, utilise des mutexes et peut supporter des accès concurrents
dans un context <em>mpmc</em>, mais elle reste limitée en terme de parallélisation.
<!--  --></p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">enqueue</span><span class="p">(</span><span class="n">queue_t</span> <span class="o">*</span><span class="n">queue</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">node_t</span> <span class="o">*</span><span class="n">node</span> <span class="o">=</span> <span class="p">(</span><span class="n">node_t</span> <span class="o">*</span><span class="p">)</span> <span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">node_t</span><span class="p">));</span>   <span class="c1">// E1</span>
    <span class="n">pthread_mutex_lock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">queue</span><span class="o">-&gt;</span><span class="n">tail_lock</span><span class="p">);</span>              <span class="c1">// E2</span>
    <span class="n">queue</span><span class="o">-&gt;</span><span class="n">tail</span><span class="o">-&gt;</span><span class="n">next</span> <span class="o">=</span> <span class="n">node</span><span class="p">;</span>                           <span class="c1">// E3</span>
    <span class="n">queue</span><span class="o">-&gt;</span><span class="n">tail</span> <span class="o">=</span> <span class="n">node</span><span class="p">;</span>                                 <span class="c1">// E4</span>
    <span class="n">pthread_mutex_unlock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">q</span><span class="o">-&gt;</span><span class="n">tail_lock</span><span class="p">);</span>                <span class="c1">// E5</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">dequeue</span><span class="p">(</span><span class="n">queue_t</span> <span class="o">*</span><span class="n">queue</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">pthread_mutex_lock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">queue</span><span class="o">-&gt;</span><span class="n">head_lock</span><span class="p">);</span>              <span class="c1">// D1</span>
    <span class="n">node_t</span> <span class="o">*</span><span class="n">node</span> <span class="o">=</span> <span class="n">queue</span><span class="o">-&gt;</span><span class="n">head</span><span class="p">;</span>                         <span class="c1">// D2</span>
    <span class="n">node_t</span> <span class="o">*</span><span class="n">new_head</span> <span class="o">=</span> <span class="n">node</span><span class="o">-&gt;</span><span class="n">next</span><span class="p">;</span>                      <span class="c1">// D3</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">new_head</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span>                               <span class="c1">// D4</span>
        <span class="k">return</span> <span class="n">pthread_mutex_unlock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">q</span><span class="o">-&gt;</span><span class="n">head_lock</span><span class="p">);</span>     <span class="c1">// D5</span>
    <span class="n">queue</span><span class="o">-&gt;</span><span class="n">head</span> <span class="o">=</span> <span class="n">new_head</span><span class="p">;</span>                             <span class="c1">// D6</span>
    <span class="n">pthread_mutex_unlock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">queue</span><span class="o">-&gt;</span><span class="n">head_lock</span><span class="p">);</span>            <span class="c1">// D7</span>
    <span class="n">free</span><span class="p">(</span><span class="n">node</span><span class="p">);</span>                                         <span class="c1">// D8</span>
<span class="p">}</span>
</code></pre></div></div>
<div class="figure-title">File "livelock-free" avec deux mutexes</div>

<p>Étant donné que mon implémentation ne possède qu’un seul consommateur, le verrou
<code class="language-plaintext highlighter-rouge">head_lock</code> ne sera pas necessaire. Les lignes D1, et D7 sont optionnelles.</p>

<p>À noter, si on retire les verrouillages et déverrouillages dans la figure
ci-dessus, on obtient strictement l’algorithme synchrone de file. Les étapes 2,
3 et 4 d’ajout dans la file sont condensés en E3 et E4. Puis pour le défilement, les
lignes D2, D3 et D6 s’occupent des étapes 2 et 3 de l’algorithme. J’ajouterai
en commentaire que les lignes E3 et D3 sont des opérations qu’on considère
comme atomiques ici. C’est-à-dire qu’elles ne peuvent pas être réalisées
strictement en même temps. C’est dans cette direction : reproduire strictement
une file synchrone, qu’on devra aller pour trouver un nouvel algorithme libéré
des <em>mutexes</em>.</p>

<p>Il faut donc passer le niveau de l’algorithme de <em>obstruction-free</em> à
<em>lock-free</em>. En premier lieu identifions les parties critiques des algorithmes
<code class="language-plaintext highlighter-rouge">push</code> et <code class="language-plaintext highlighter-rouge">pop</code>. Pour enfiler une valeur, a priori, créer un noeud n’est pas
critique. Trouver la fin de file devient plus difficile. Pour reprendre
l’exemple précédent de choses qui pourraient mal se passer, la fin de file est
susceptible de changer juste avant de passer à la phase 3 ou 4 de l’algorithme.
La récupération de la fin de file, phase 2, n’est pas critique si l’écriture
est conditionnée par le <em>non-changement</em> de la variable, grâce à un <i>Compare
And Swap/Exchange</i>. Dans l’exemple lock-free <code>int c = load(&amp;i); cas(&amp;i,
c, 2);</code>, la partie critique se trouve uniquement dans le <i>compare and
swap</i>, si la valeur de <em>i</em> change entre l’opération de lecture et celle
d’écriture, il est normal de vouloir annuler la modification. Les phases
d’écritures, phase 3 et 4, sont des changements qu’il vaudrait mieux faire sous
condition que la fin de file ainsi que son pointeur <em>next</em> n’aient pas changé.
Plus exactement, si plusieurs threads essaient de modifier la fin de file en
commençant par modifier son pointeur <em>next</em>, utilisez comme simple condition :
<i>le pointeur next est vide, je le modifie si effectivement il est vide</i>
suffis pour résoudre les <i>data races</i>.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">tail</span> <span class="o">=</span> <span class="k">self</span><span class="py">.tail</span><span class="nf">.load</span><span class="p">();</span>                            <span class="c1">// P1</span>
<span class="k">let</span> <span class="n">next</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">tail</span><span class="p">)</span><span class="py">.next</span><span class="nf">.load</span><span class="p">();</span>                         <span class="c1">// P2</span>
<span class="k">if</span> <span class="n">next</span><span class="nf">.is_null</span><span class="p">()</span> <span class="p">{</span>                                     <span class="c1">// P3</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="n">tail</span><span class="p">)</span><span class="py">.next</span><span class="nf">.compare_exchange</span><span class="p">(</span><span class="n">next</span><span class="p">,</span> <span class="n">node</span><span class="p">)</span> <span class="p">{</span>      <span class="c1">// P4</span>
        <span class="k">self</span><span class="py">.tail</span><span class="nf">.compare_exchange</span><span class="p">(</span><span class="n">tail</span><span class="p">,</span> <span class="n">node</span><span class="p">);</span>         <span class="c1">// P5</span>
        <span class="k">return</span><span class="p">;</span>                                         <span class="c1">// P6</span>
    <span class="p">}</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="k">self</span><span class="py">.tail</span><span class="nf">.compare_exchange</span><span class="p">(</span><span class="n">tail</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span>             <span class="c1">// P7</span>
<span class="p">}</span>
</code></pre></div></div>
<div class="figure-title">Extrait de la fonction Push, <br />
implémentation en Rust de la file de Mickael &amp; Scott</div>

<p>Cet extrait de la méthode <code class="language-plaintext highlighter-rouge">enqueue</code> de mon implémentation en Rust de la file
d’attente non-bloquante, simplifiée pour l’occasion, réalise strictement les
mêmes actions que l’implémentation livelock-free. On trouve les lignes E3 et E5
très ressemblantes à P4 et P5, outre le fait que la condition pour assigner
<code class="language-plaintext highlighter-rouge">next</code> et <code class="language-plaintext highlighter-rouge">tail</code> est que <code class="language-plaintext highlighter-rouge">next</code> n’ai pas changé entre P1 et P4. Tester le
retour de P5 n’est pas nécessaire pour les deux raisons suivantes. Premièrement
deux threads ne peuvent pas valider la condition P4 simultanément.
Deuxièmement, si un thread A valide la condition P4, un second thread B ayant
récupéré une copie de <code class="language-plaintext highlighter-rouge">next</code> l’instant d’après, ne validera ni P4 ni P3. Le
thread B tombera dans P7 pour essayer de mettre à jour la fin de file,
exactement comme en P5.</p>

<p>La ligne P7 peut paraître superflue à première vue, elle est le pendant de la
ligne P5 qui sera de toute manière executée extrèmement rapidement. Cette
ligne, optionnelle en un sens, nous assure cette vitesse de changement de la
fin de file ainsi que l’indépendance des threads. Il se pourrait qu’après avoir
validé P4, le thread A ayant terminé d’ajouter un noeud, soit “endormi” et
laisse temporairement la file dans un état inconsistent. Ce court laps de temps
pourrait faire boucler le thread B sur P1, P2 et P3 un certain nombre de fois,
ce qui ralentirait le programme. Alors P7 trouve toute son utilité, si A
<em>dort</em>, B termine le travail, recommence, et réussi.</p>

<p>Une deuxième implémentation, celle qu’on peut trouver dans les bibliothèques
standards modernes, ne se préoccupe pas d’aider les autres threads. La file que
je présente n’est pas particulièrement optimisée pour un <em>mpsc</em>. Elle est bien
plus générique, elle cherche la performance dans des situations très variées.
Le fait de mettre à jour la file en anticipant l’action d’un thread parallèle
est une mécanique pessimiste, répétée à la ligne Q7 dans la figure ci-dessous,
mais qui dans certains cas peut se révéler indispensable.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">head</span> <span class="o">=</span> <span class="k">self</span><span class="py">.head</span><span class="nf">.load</span><span class="p">();</span>                            <span class="c1">// Q1</span>
<span class="k">let</span> <span class="n">tail</span> <span class="o">=</span> <span class="k">self</span><span class="py">.tail</span><span class="nf">.load</span><span class="p">();</span>                            <span class="c1">// Q2</span>
<span class="k">let</span> <span class="n">next</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">head</span><span class="p">)</span><span class="py">.next</span><span class="nf">.load</span><span class="p">();</span>                         <span class="c1">// Q3</span>
<span class="k">if</span> <span class="nn">std</span><span class="p">::</span><span class="nn">ptr</span><span class="p">::</span><span class="nf">eq</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="n">tail</span><span class="p">)</span> <span class="p">{</span>                           <span class="c1">// Q4</span>
    <span class="k">if</span> <span class="n">next</span><span class="nf">.is_null</span><span class="p">()</span> <span class="p">{</span>                                 <span class="c1">// Q5</span>
        <span class="k">return</span> <span class="nb">None</span><span class="p">;</span>                                    <span class="c1">// Q6</span>
    <span class="p">}</span>
    <span class="k">self</span><span class="py">.tail</span><span class="nf">.compare_exchange</span><span class="p">(</span><span class="n">tail</span><span class="p">,</span> <span class="n">next</span><span class="p">);</span>             <span class="c1">// Q7</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">ret</span> <span class="o">=</span> <span class="p">(</span><span class="o">*</span><span class="n">next</span><span class="p">)</span><span class="py">.value</span><span class="p">;</span>                            <span class="c1">// Q8</span>
    <span class="k">if</span> <span class="k">self</span><span class="py">.head</span><span class="nf">.compare_exchange</span><span class="p">(</span><span class="n">head</span><span class="p">,</span> <span class="n">next</span><span class="p">)</span><span class="nf">.is_ok</span><span class="p">()</span> <span class="p">{</span> <span class="c1">// Q9</span>
        <span class="nf">drop</span><span class="p">(</span><span class="n">head</span><span class="p">);</span>                                     <span class="c1">// Q10</span>
        <span class="k">return</span> <span class="nf">Some</span><span class="p">(</span><span class="n">ret</span><span class="p">);</span>                               <span class="c1">// Q11</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<div class="figure-title">Extrait de la fonction Pop, <br />
implémentation en Rust de la file de Mickael &amp; Scott</div>

<!-- modif après relecture d'Yvan -->
<blockquote>
  <p>Un algorithme comme celui-ci qui aide les threads à terminer leurs opérations
d’écriture, aide forcement la lecture à avancer. Un algorithme écrit en faisant
attention à ces détails garantit qu’un thread pourra toujours faire avancer son
propre état de façon indépendante et ne restera jamais bloqué par d’autres
threads. On dit de ces algorithmes qu’ils sont <em>“linéarisables”</em>.</p>

  <p>Veuillez excuser l’emploi du terme technique “linéarisable”, je me propose de
vous en offrir une définition concise au sein d’une parenthèse dédiée. Pour
commencer, toute routine d’un algorithme a un début et une fin (si la
sémantique le demande). Si le début est simple à observer chronologiquement, la
fin est souvent moins déterminée. La routine <em>Pop</em> ci-dessus, peut
potentiellement finir à Q11, pour cela, elle devra préalablement valider la
ligne Q9. En réalité, on peut affirmer que cette routine termine ses effets
avec succès lorsque le <i>compare and swap</i> s’exécute correctement, la suite
reste du simple utilitaire pratique. Au vu déjà de cet aspect temporel des
appels et des retours, nous pouvons créer un historique tel que : <i>“j’appelle
push(A)”</i> puis <i>“A est dans la liste”</i>. Combiné avec la routine <em>Pop</em> nous
pourrions observer cette suite d’événements :</p>

  <ol>
    <li>push(A)</li>
    <li>A est dans la liste</li>
    <li>pop()</li>
    <li>pop retourne A</li>
  </ol>

  <p>Vous remarquerez que chaque appel d’une fonction est suivi par son résultat, ce
qui nous rassure d’un point de vue logique. <em>Pop</em> ne retourne pas de valeur
avant son appel, de même, la réponse <i>“A est bien dans la liste”</i> précède
strictement le retour de <em>Pop</em>, ceci nous confirme que l’espace-temps dans
lequel nous testons notre algorithme est bien linéaire. Autrement dit, nous
pouvons raisonner à propos de son exactitude. Un deuxième scénario réaliste
pourrait être : <em>Pop</em> ne retourne pas d’information en un laps de temps
raisonnable. Comment dans ce cas juger de du déterminisme ainsi que de la
linéarité de l’historique sémantique ? <em>Pop</em> finira-t-il un jour ? En fin de
compte, un algorithme linéarisable doit respecter certaines contraintes
temporelles. Il faudrait, entre autres, qu’un appel à une de ces routines
<i>donne l’impression</i> de se terminer instantanément après son appel. Or,
<i>“donner l’impréssion de”</i> implique une vision subjective et complexe à
déterminer pour la plupart des algorithmes. Ceci nous amènerai à des réflexions
trop eloignées du périmètre de l’informatique. Une seconde définition
équivalente, plus simple à prouver, est la suivante : entre le début de la
routine et sa fin, il doit exister une ou plusieurs étapes où la routine a fait
effet. Pour <em>Pop</em>, par exemple Q9 peut être cette ligne à condition qu’une de
ces itérations lui permette de faire réussir l’échange. Q9 est ici le <em>point de
linéarisation</em> de la routine. Vous l’aurez compris, ces contraintes sont
primordiales pour pouvoir raisonner correctement à propos d’un algorithme, et
éviter des incohérences dans de nombreux contextes. Concluons cette parenthèse
en dépit du fait qu’il subsiste encore un abondant corpus de réflexions à
opérer sur ce thème.
<!-- --></p>
</blockquote>

<p>Reprenons l’implémentation du <em>mpsc</em>. Comme avec l’algorithme livelock-free
présenté précédemment, il n’est pas nécessaire d’utiliser de variable atomique
pour le pointeur vers la tête de file. Si le cas d’usage nous garantit qu’un
unique thread pourra accéder à cette fonction, pas nécessairement le même
thread à chaque appel, la ligne Q9 peut être remplacée sans hésiter par une
écriture tout ce qu’il y a de plus banale. Dans le cas générique, ce mécanisme
protège les consommateurs de plusieurs scénarios de duplication de données et de
<em>data races</em>. Il protège entre autres des doubles libérations de mémoire, on
peut libérer la mémoire de l’ancien noeud sans crainte dans cet algorithme car
l’échange en Q9 ne peut se faire que par un seul thread. Après l’échange de
<em>head</em> et <em>next</em>, la <em>head</em> précédente est inaccessible à tout autres threads.
Avec certitude, on ne déréférencera jamais un pointeur nul et on ne cherchera
pas non plus à libérer sa mémoire deux fois.</p>

<p>Les deux extraits de code précédent sont tirés d’une version d’implémentation
d’une <em>Michael &amp; Scott Queue</em>. L’algorithme en question corrige normalement le
problème appelé <em>ABA</em>. Cette partie n’est pas présentée ici, notez cependant
que dans un algorithme linéarisable, la plupart, pour ne pas dire tous,
résolvent l’<em>ABA</em> en utilisant un compteur pour vérifier la consistance entre
les noeuds. Chaque noeud aura un identifiant unique en plus d’une adresse et
d’un contenu, évitant les confusions.</p>

<!-- Ajout après info : crossbeam qui remplace la std -->

<blockquote>
  <p>L’implémentation de la bibliothèque standard de Rust a évolué pendant que
j’écrivais ces lignes. Aujourd’hui l’implémentation de <em>mpsc / mpmc</em>
ressemblerait plus à une <em>Mickael &amp; Scott Queue</em> comme si dessus avec quelques
améliorations pour la partie <em>unbounded</em> et est resté sur une proposition de
Dmitry Vyukov’s pour la partie <em>bounded</em>. N’ayant pas d’autres informations
pour le moment, je reserve plus de détails dans des chapitres ultérieurs.</p>
</blockquote>

<p>Si vous développez en Rust, l’implémentation dans la bibliothèque standard
respecte les critères d’une file <em>lock-free</em> non intrusive de multiples
producteurs et unique consommateur. Dans le pseudocode suivant, si un
producteur p1 exécute R1 et R2, puis un producteur p2 exécute R1, R2 et R3,
puis p1 termine la routine avec R3, en considérent les paragraphes et
exemples précédents, pensez vous que cet algorithme est linéarisable ? Pourquoi
ne peut-il pas y avoir d’<em>ABA</em> avec cette méthode ?</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">create</span><span class="p">():</span>
    <span class="k">self</span><span class="py">.tail</span> <span class="o">=</span> <span class="k">self</span><span class="py">.head</span> <span class="o">=</span> <span class="n">dummy_ptr</span><span class="p">;</span>

<span class="k">fn</span> <span class="nf">push</span><span class="p">():</span>
    <span class="k">let</span> <span class="n">node</span> <span class="o">=</span> <span class="nn">Node</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>             <span class="c1">// R1</span>
    <span class="k">let</span> <span class="n">prev</span> <span class="o">=</span> <span class="k">self</span><span class="py">.next</span><span class="nf">.swap</span><span class="p">(</span><span class="n">node</span><span class="p">);</span>    <span class="c1">// R2</span>
    <span class="n">prev</span><span class="k">-&gt;</span><span class="n">next</span><span class="nf">.store</span><span class="p">(</span><span class="n">node</span><span class="p">);</span>             <span class="c1">// R3</span>

<span class="k">fn</span> <span class="nf">pop</span><span class="p">():</span>
    <span class="k">let</span> <span class="n">tail</span> <span class="o">=</span> <span class="o">*</span><span class="k">self</span><span class="py">.tail</span><span class="nf">.get</span><span class="p">();</span>        <span class="c1">// S1</span>
    <span class="k">let</span> <span class="n">next</span> <span class="o">=</span> <span class="n">tail</span><span class="k">-&gt;</span><span class="n">next</span><span class="nf">.load</span><span class="p">();</span>       <span class="c1">// S2</span>
    <span class="k">if</span> <span class="o">!</span><span class="n">next</span><span class="nf">.is_null</span><span class="p">():</span>                 <span class="c1">// S3</span>
        <span class="o">*</span><span class="k">self</span><span class="py">.tail</span><span class="nf">.get</span><span class="p">()</span> <span class="o">=</span> <span class="n">next</span><span class="p">;</span>        <span class="c1">// S4</span>
        <span class="nf">drop</span><span class="p">(</span><span class="n">tail</span><span class="p">);</span>                     <span class="c1">// S5</span>
        <span class="k">return</span> <span class="nb">Success</span>                  <span class="c1">// S6</span>
    <span class="k">if</span> <span class="k">self</span><span class="py">.head</span><span class="nf">.load</span><span class="p">()</span> <span class="o">==</span> <span class="n">tail</span><span class="p">:</span>        <span class="c1">// S7</span>
        <span class="k">return</span> <span class="n">Empty</span>                    <span class="c1">// S8</span>
    <span class="k">return</span> <span class="n">WaitingAnInput</span>               <span class="c1">// S9</span>
</code></pre></div></div>

<!-- Cet algorithme à tout d'un wait-free, alors pourquoi le classer comme lock-free.
A voir dans un bonus potentiellement -->

<p>Pour conclure ce chapitre, je voudrais attirer l’attention sur les lignes S7,
S8 et S9 de la figure précédente. L’implémentation de ce test est tout à fait
optionnelle, si le thread consommateur n’a pas encore accès à une information,
bien qu’un producteur soit en train d’en ajouter une, la réponse <em>Empty</em> reste
acceptable. D’autant plus que dans un thread A qui sera différent du thread du
consommateur, l’exécution de R1 peut potentiellement commencer lorsque S7 est
validé, alors l’inconsistance de la file ne sera pas détectée. Nous pouvons penser
que l’usage d’une file par rapport à une autre a toujours une raison valable,
qu’un algorithme ne peut pas varier sous peine d’un danger imminent de
comportement indéfini. Pour le moment, il a été démontré le contraire. Dans certains
cas, on peut retirer des verrous ou des accès atomiques et tout ira bien.
Certains préféreront un algorithme linéarisable, mais tout est une question de
contexte, d’opinion, de dosage, d’évaluation de risque, c’est pourquoi une
implémentation qui est plus rapide dans 99% des cas et extrêmement coûteux dans
le dernier a sa place dans une bibliothèque standard. C’est pourquoi on peut
aussi espérer détecter une inconsistance (S7-S9), car dans ce cas, on sait
comment réagir au mieux et améliorer, du fait, une vitesse moyenne d’exécution.</p>

<h2 id="chapitre-8---machine-à-états-industrielle">Chapitre 8 - Machine à états industrielle</h2>

<p>Il peut arriver qu’une machine à états soit nécessaire dans votre programme car
pour communiquer correctement avec des composants embarqués. Il se peut
également que les événements reçus de ces composants soient invalides, arrivent
à des moments imprévus, se répètent plusieurs fois, ou ne soient pas dans
l’ordre attendu.</p>

<p>En utilisant la bibliothèque Reagir, définissons une machine à états un peu
plus réaliste. Cette fois-ci, la lecture de l’entrée utilisateur est parallèle
à l’exécution, donc on peut recevoir des événements à tout moment. Nous ne
pouvons pas garantir que les composants du système nous enverrons des
signaux lisibles ou cohérents. L’automate ressemble à ceci :</p>

<p align="center">
  <img width="400" src="/assets/img/state_machine_1/diagrame_d_etats_2.png" />
</p>

<p>Le code doit être clair et précis. Il est important de noter que dans le milieu
industriel, les machines à états évoluent souvent plus rapidement que le reste
du programme, il est donc essentiel de maintenir un code facile à modifier. Par
rapport à l’exemple précédent, la fonction state_machine ne varie presque pas.
La structure de l’état ne devrait contenir que les fonctions d’étapes qui
produisent les effets de bord, ainsi que les éléments nécessaires à
l’application, comme le contexte. Les fonctions, dans l’exemple suivant,
toujours appelées de dynamiquement, définissent également pour l’état courant
les événements attendus.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">State_t</span> <span class="n">state_A</span> <span class="o">=</span> <span class="p">{</span><span class="n">fn_state_A</span><span class="p">};</span>
<span class="c1">// [...]</span>
<span class="n">State_t</span> <span class="n">state_E</span> <span class="o">=</span> <span class="p">{</span><span class="n">fn_state_E</span><span class="p">};</span>

<span class="kt">void</span> <span class="nf">fn_state_A</span><span class="p">(</span><span class="n">State_t</span> <span class="o">*</span><span class="n">_</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">onEvent</span><span class="p">(</span><span class="s">"gotoB"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">state_B</span><span class="p">);</span>
    <span class="n">onEvent</span><span class="p">(</span><span class="s">"gotoC"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">state_C</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">fn_state_B</span><span class="p">(</span><span class="n">State_t</span> <span class="o">*</span><span class="n">_</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">onEvent</span><span class="p">(</span><span class="s">"gotoD"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">state_D</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">fn_state_C</span><span class="p">(</span><span class="n">State_t</span> <span class="o">*</span><span class="n">_</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">onEvent</span><span class="p">(</span><span class="s">"gotoD"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">state_D</span><span class="p">);</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">fn_state_D</span><span class="p">(</span><span class="n">State_t</span> <span class="o">*</span><span class="n">_</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">onEvent</span><span class="p">(</span><span class="s">"restart"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">state_A</span><span class="p">);</span>
    <span class="n">onEvent</span><span class="p">(</span><span class="s">"stop"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">state_E</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Lorsque le programme entre dans l’état A, il execute la fonction associée
<code class="language-plaintext highlighter-rouge">fn_state_A</code>. Laquelle, à part les effets de bord qu’elle implique, peut
définir quelque part que la machine s’attend à présent à un des évenements
<code class="language-plaintext highlighter-rouge">gotoB</code> et <code class="language-plaintext highlighter-rouge">gotoC</code> et aucun autre. Le signal d’un de ces évenements entrainera
respectivement le passage à l’état B ou C. Il est important de remarquer les
avantages de décrire sa machine à états de cette manière : elle est extrèmement
fléxible et lisible. Avec cette technique de base, il est possible d’écrire des
programmes d’une étonnante compléxité.</p>

<p>En ce qui concerne la communication avec d’autres composants, il est
important de noter que chaque état peut recevoir un ou plusieurs événements, dû
à du bruit ou à un mauvais traitement du signal dans une partie plus bas
niveau. Dans notre exemple, nous recevons du texte, mais cela pourrait être
n’importe quel signal externe ou interne. Admettons que nous soyons en train de
communiquer avec des composants qui fonctionnent en temps réel, et qu’un
message tel que <code class="language-plaintext highlighter-rouge">gotoB</code> puisse être reçu plusieurs fois avant que la partie
matérielle responsable ne se mette à jour. Pour gérer ces cas, il est judicieux
de centraliser les changements d’état en utilisant une fonction de réduction.</p>

<p>Une <em>fonction de réduction</em> donne la possibilité de définir les mises à jour de
l’état en fonction de l’état actuel et d’un nouvel évènement. Elle est appelée
en amont de l’exécution d’un état et peut décider si valider ou non une
transition. L’état suivant est définit par la valeur de retour de la fonction
de réduction. Si cette valeur est nulle, la bibliothèque ignorera l’évènement.
Cette fonction permet surtout de centraliser les transitions, vous pouvez
rendre votre code plus lisible et maintenable en séparant clairement les
différentes actions qui peuvent modifier l’état de votre application.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="o">*</span><span class="nf">find_next_state</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">old_state</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">event</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">static</span> <span class="kt">char</span> <span class="n">previous_event</span><span class="p">[</span><span class="mi">30</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="sc">'\0'</span><span class="p">};</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">strcmp</span><span class="p">(</span><span class="n">previous_event</span><span class="p">,</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">event</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>         <span class="c1">// P1</span>
        <span class="k">return</span> <span class="nb">NULL</span><span class="p">;</span>
    <span class="kt">void</span> <span class="o">*</span><span class="n">state</span> <span class="o">=</span> <span class="n">hashmap</span><span class="p">[</span><span class="n">hash</span><span class="p">(</span><span class="n">event</span><span class="p">)];</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">state</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span>                                      <span class="c1">// P2</span>
        <span class="n">memcpy</span><span class="p">(</span><span class="n">previous_event</span><span class="p">,</span> <span class="n">event</span><span class="p">,</span> <span class="mi">30</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">state</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="o">*</span><span class="nf">reducer</span><span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="n">old_state</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">event</span><span class="p">)</span>
<span class="p">{</span>
    <span class="kt">void</span> <span class="o">*</span><span class="n">ret</span> <span class="o">=</span> <span class="n">find_next_state</span><span class="p">(</span><span class="n">old_state</span><span class="p">,</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="p">)</span> <span class="n">event</span><span class="p">);</span>
    <span class="n">free</span><span class="p">(</span><span class="n">event</span><span class="p">);</span>
    <span class="k">return</span> <span class="n">ret</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Dans la figure précédente, la ligne P1 protège contre des signaux dupliqués. On
ne peut recevoir un signal qu’une seule fois, sa répétition est interdite.
Notez qu’en pratique, vous pourriez souhaiter ajouter quelques exceptions à
cette règle. Par exemple, il est possible que vous vouliez recevoir un signal
<code class="language-plaintext highlighter-rouge">next</code> plusieurs fois. Pensez alors à ajouter des fonctions de vérification. Ce
problème est très similaire à un autre dont il faut tenir compte avec de la
programmation atomique, ce qui relie enfin concrètement nos deux thématiques.
Regardez la figure Rust ci-dessous, ce morceau de code modifie la valeur du
paramètre et signal en modifiant un flag qu’elle a été modifiée, comme pour le
<em>spinlock</em> vu précédemment. En C ou C++, on n’aurait même pas besoin de
préciser que ces paramètres sont atomiques, ni qu’elles sont cachées derrière
un compteur de référence. Malgré tout, la particularitée de Rust à être <em>memory
safe</em> n’exempte pas ce code d’un possible <em>data race</em>. Lorsqu’on ne précise pas
l’ordre, ou qu’on donne un ordre <em>Relaxed</em>, à l’écriture de variable, on ne
peut pas confirmer avec certitude que <code class="language-plaintext highlighter-rouge">val</code> sera toujours modifié avant
<code class="language-plaintext highlighter-rouge">modified_flag</code>. C’est cela que l’on nomme un <em>spurious wake up</em>.</p>

<p>Lorsqu’on ajoute à la place de P1 une exception, on doit toujours y ajouter si
nécessaire une protection. En général, une variable tierce, un <em>timestamp</em> ou
un identifiant qui nous permettra de vérifier si l’évènement est unique.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">modify_val</span><span class="p">(</span><span class="n">modified_flag</span><span class="p">:</span> <span class="nb">Arc</span><span class="o">&lt;</span><span class="n">AtomicBool</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">val</span><span class="p">:</span> <span class="nb">Arc</span><span class="o">&lt;</span><span class="n">AtomicU32</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">val</span><span class="nf">.store</span><span class="p">(</span><span class="mi">42</span><span class="p">,</span> <span class="n">Relaxed</span><span class="p">);</span>
    <span class="n">modified_flag</span><span class="nf">.store</span><span class="p">(</span><span class="k">true</span><span class="p">,</span> <span class="n">Relaxed</span><span class="p">);</span>
<span class="p">}</span>

<span class="k">fn</span> <span class="nf">read_val</span><span class="p">(</span><span class="n">modified_flag</span><span class="p">:</span> <span class="nb">Arc</span><span class="o">&lt;</span><span class="n">AtomicBool</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">val</span><span class="p">:</span> <span class="nb">Arc</span><span class="o">&lt;</span><span class="n">AtomicU32</span><span class="o">&gt;</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">while</span> <span class="n">modified_flad</span><span class="nf">.load</span><span class="p">(</span><span class="n">Relaxed</span><span class="p">)</span> <span class="o">==</span> <span class="k">false</span> <span class="p">{}</span>
    <span class="nd">assert_eq!</span><span class="p">(</span><span class="n">val</span><span class="nf">.load</span><span class="p">(</span><span class="n">Relaxed</span><span class="p">),</span> <span class="mi">42</span><span class="p">);</span> <span class="c1">// Peut fail</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Gardons à l’esprit que ce code est exécuté de façon synchrone, ça signifie que
l’état actuel a déjà été appliqué. Premièrement, on ne peut pas être
simultanément dans une fonction comme <code class="language-plaintext highlighter-rouge">fn_state_A</code> et dans la fonction de
réduction. Deuxièmement, la fonction de réduction est appelée avant que l’état
fasse ses effets. Conclusion, quand on entre dans la fonction de réduction, la
machine à états est abonnée aux seuls évènements attendus dans son contexte
actuel. La ligne P2 nous permet d’ignorer ces évènements inatendus. Si nous
sommes à l’état B, le signal <code class="language-plaintext highlighter-rouge">gotoC</code> sera ignoré. Ça peut être un comportement
erroné, dans certains cas, on peut souhaiter que l’état devienne vraiment C
dans la mesure du possible. Si besoin, j’ajouterai un état transitoire qui
tentera d’annuler les effets de bord de l’état précédent.</p>

<p>Représenter son programme grâce à un diagramme d’états et de transition
facilite le développement d’applications complexe. On se fait un cadeau en
décrivant à haut niveau le fonctionnement de son programme. On peut vérifier
l’exactitude, les besoins, transmettre une connaissance rapidement dans une
équipe et améliorer la communication entre les composants.</p>

<h2 id="chapitre-9---le-problème-du-dernier-état">Chapitre 9 - Le problème du dernier état</h2>

<p>Revenons sur la file d’évenement un instant et comment elle est implémentée.
Lorsque dans la boucle de la machine à états le consommateur attend un nouvel
évènement à traiter, il est préférable de permettre au CPU d’utiliser le coeur
inactif durant l’attente. Évidemment, ça dépend des cas, encore une fois.</p>

<p>On souhaite utiliser un file non-bloquante et, dans la mesure du possible, ne
pas invoquer de verrou. Une implémentation similaire à celle de Réagir, qui
utilise des variables conditionnelles, pourrait ressembler à la figure
ci-dessous. La boucle de réception tente dans un premier temps de tirer un
élément de la file, en cas de réussite (R5) il traite l’entrée, en cas d’échec,
il attend une nouvelle entrée et un signal (S2). L’attente en R4 symbolise donc
l’attente d’un signal dans le cas où la file serait vide et <code class="language-plaintext highlighter-rouge">push</code> est notre
variable conditionnelle.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">send</span><span class="p">(</span><span class="n">e</span><span class="p">):</span>
    <span class="n">queue</span><span class="nf">.push</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>                  <span class="c1">// S1</span>
    <span class="nf">signal</span><span class="p">(</span><span class="o">&amp;</span><span class="n">push</span><span class="p">)</span>                   <span class="c1">// S2</span>

<span class="nf">receiver_loop</span><span class="p">():</span>
    <span class="k">let</span> <span class="n">e</span> <span class="o">=</span> <span class="n">queue</span><span class="nf">.pop</span><span class="p">();</span>            <span class="c1">// R1</span>
    <span class="k">if</span> <span class="n">e</span> <span class="o">==</span> <span class="n">Null</span><span class="p">:</span>                   <span class="c1">// R2</span>
        <span class="k">let</span> <span class="n">guard</span> <span class="o">=</span> <span class="nf">lock</span><span class="p">(</span><span class="o">&amp;</span><span class="n">mutex</span><span class="p">);</span>   <span class="c1">// R3</span>
        <span class="nf">wait</span><span class="p">(</span><span class="o">&amp;</span><span class="n">push</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">mutex</span><span class="p">);</span>        <span class="c1">// R4</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="nf">received</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>                <span class="c1">// R5</span>
</code></pre></div></div>

<p>On remarque dans un premier temps qu’on utilise un verrou autour de la variable
conditionnelle. Purement pour respecter les bonnes pratiques, celui-ci est
optionnel. Au cas où le fonctionnement des <em>cond_var</em> le permettait, on s’en
passerait. Mais cette implémentation a un plus gros défaut. Si le consommateur
vient d’échouer à lire une entrée, au moment où il entre dans R3, un producteur
peut entrer en action, terminer S1 et S2, avant que R4 ne soit invoqué par le
consommateur, le laissant alors dans un état de veille avec une entrée (ou
plus) dans la file. En fait, le problème est d’informer au thread du
consommateur de ne pas se mettre en veille entre R2 et R4, ce qui est
impossible sans d’autres mécanismes de synchronisation.</p>

<p>La première technique, si je choisis de continuer avec des variables
conditionnelles et des verrous, utilise le concepte de sémaphore. Or, si je
persiste, je finis dans tous les cas dans une file synchrone où, au mieux,
quelques threads pourront être parallélisés avec difficulté. La deuxième
méthode, la plus moderne, utilise des <em>futex</em>. Dans ces chapitres, je n’ai pas
présenté le fonctionnement des variables conditionnelles, ni même des
<em>mutexes</em>. Je ne vais pas non plus entrer dans les détails des <em>futex</em>, mais
les exemples qui suivront permettront sûrement d’éclaircir cet aspect de
l’informatique pour ceux qui n’ont jamais fait l’expérience de ce mécanisme de
synchronisation.</p>

<p>Prenons n’importe quelle file <em>lock-free</em> qu’on peut trouver, que ça soit celle
de la bibliothèque standard <em>Rust</em> ou bien une plus générique et linéarisable.
Nous savons que le retour de la routine <em>pop</em> peut être nul, même si un
producteur vient d’être appelé. Dans la file <em>mpsc</em> de <em>Rust</em>, on peut avec un
peu de chance identifier cet état d’inconsistence, il semble que dans ce cas
précis, boucler sur la routine <em>pop</em> jusqu’à recevoir de la donnée soit une
bonne chose à faire. Dans l’autre cas, autant plus probable, il faut savoir
gérer le status de la structure <em>mpsc</em> en ne sachant rien des activités des
threads parallèles.</p>

<p>Utiliser des futexes dans cette situation est approprié. En quelques mots, ce
mécanisme permet de créer un verrou si une variable atomique remplit une
condition. Exactement comme pour le <em>compare and swap</em> , où l’objectif serait
d’enclencher l’attente d’un signal. La figure ci-dessous ressemble plus ou
moins à ce qu’on pourrait réaliser avec des sémaphores de façon plus moderne.
De plus, l’utilisation de <em>swap</em> qui retourne l’état précédent et de
<em>fetch_sub</em> qui passera selon les cas du status Notified à Running et de
Running à Waiting, fait que cette partie de l’implémentation est <em>wait-free</em>.
Cette méthode est aussi connue sous le nom de <em>“thread parker”</em>, le
consommateur attend jusqu’à ce qu’il soit notifié, à condition de ne pas déjà
être notifié.</p>

<p>Notez également deux points. Premièrement, la boucle B5, celle-ci protège d’un
possible <em>spurious wake up</em>, qu’on a déjà décrit, de la part du système,
détécté par le test B7. Deuxièmement, ce n’est pas évident dans le pseudocode
qui suit, appeler un futex aujourd’hui passe par un appel système, et donc
s’avère différent pour chaque architecture.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">Notified</span> <span class="o">=</span> <span class="mi">2</span><span class="p">,</span> <span class="n">Running</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">Waiting</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">let</span> <span class="n">status</span> <span class="o">=</span> <span class="n">Running</span><span class="p">;</span>

<span class="nf">send</span><span class="p">(</span><span class="n">e</span><span class="p">):</span>
    <span class="n">queue</span><span class="nf">.push</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>                              <span class="c1">// A1</span>
    <span class="k">if</span> <span class="n">status</span><span class="nf">.swap</span><span class="p">(</span><span class="n">Notified</span><span class="p">)</span> <span class="o">==</span> <span class="n">Waiting</span><span class="p">:</span>        <span class="c1">// A2</span>
        <span class="nf">futex_wake</span><span class="p">(</span><span class="o">&amp;</span><span class="n">status</span><span class="p">);</span>                    <span class="c1">// A3</span>

<span class="nf">receiver_loop</span><span class="p">():</span>
    <span class="k">let</span> <span class="n">e</span> <span class="o">=</span> <span class="n">queue</span><span class="nf">.pop</span><span class="p">();</span>                        <span class="c1">// B1</span>
    <span class="k">if</span> <span class="n">e</span> <span class="o">==</span> <span class="n">Null</span><span class="p">:</span>                               <span class="c1">// B2</span>
        <span class="k">if</span> <span class="n">status</span><span class="nf">.fetch_sub</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">==</span> <span class="n">Notified</span><span class="p">:</span>     <span class="c1">// B3</span>
            <span class="k">return</span><span class="p">;</span>                             <span class="c1">// B4</span>
        <span class="k">loop</span><span class="p">:</span>                                   <span class="c1">// B5</span>
            <span class="nf">futex_wait</span><span class="p">(</span><span class="o">&amp;</span><span class="n">status</span><span class="p">,</span> <span class="n">Waiting</span><span class="p">)</span>        <span class="c1">// B6</span>
            <span class="k">if</span> <span class="n">status</span><span class="nf">.cas</span><span class="p">(</span><span class="n">Notified</span><span class="p">,</span> <span class="n">Running</span><span class="p">):</span>   <span class="c1">// B7</span>
                <span class="k">break</span><span class="p">;</span>                          <span class="c1">// B8</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="nf">received</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>                            <span class="c1">// B9</span>
</code></pre></div></div>

<h2 id="premier-récapitulatif">Premier récapitulatif</h2>

<p>Malheureusement, je ne suis pas en mesure de formuler une conclusion définitive
à propos des machines à états ni de la programmation multithreadé, ce domaine
étant en constante évolution (une telle conclusion est probablement
irréalisable). Toutefois, je peux avancer quelques observations basées sur mes
dernières lectures et conversations.</p>

<p>Au cours de mes investigations, j’ai remarqué des similitudes entre les
développements récents et les réflexions exposées par Pierre Boule dans son
oeuvre <em>“La planète des singes”</em>. Les travaux publiés entre 1990 et 2010
semblent avoir eu une profonde influence sur la dernière décénie. Une
explication plausible est que nous soyons réellement inspirés par les
fondateurs de l’informatique, ce qui peut expliquer en partie notre tendance à
imiter les développements antérieurs.</p>

<p>Pour ma défense, un développeur expérimenté peut parfois comprendre le
fonctionnement d’outils qu’il utilise depuis longtemps, comme un bûcheron qui
saisit enfin le fonctionnement de la hache qu’il manie. De plus, il peut être
utile de vulgariser certaines connaissances pour les rendre accessibles à un
public plus large. Cependant, nous sommes en droit de supposer que la
connaissance peut se perdre avant d’être redécouverte de génération en
génération. Dans ce cas, nous ferions mieux de lire les premiers travaux pour
comprendre les erreurs du passé ainsi que les “nouvelles” techniques de
programmation.</p>

<p>En résumé, je vous suggère d’aller plus en détail sur certains points que nous
avons abordés. Pour comprendre les problèmes de linéarisations, vous pouvez
lire les raisons du changement du <em>mpsc</em> de la bibliothèque standard Rust. Pour
les machines à états, vous pouvez explorer leur utilisation dans la
reproductibilité, le calcul à la volée et les algorithmes distribués. Vous
pouvez également lire l’implémentation de la bibliothèque <em>Reagir</em> et
comprendre pourquoi il serait vain de tester chaque entrée dans la routine
<code class="language-plaintext highlighter-rouge">dispatch</code>. Vous pouvez imaginer de nouvelles implémentations en C, de
nouvelles représentations et essayer d’autogénérer une machine à état à partir
d’un format BNF. Enfin, vous pouvez prendre de l’avance sur mon prochain
article en proposant des implémentations dans des langages plus modernes et les
comparer avec les méthodes existantes ou en développement.</p>]]></content><author><name>Adrien Zinger</name></author><summary type="html"><![CDATA[TL;DR Article, essai, présentation non-exhaustive, je présente ici un peu de programmation multithreadé et d'implémentation de machine à états. Si j'échoue à faire comprendre pour quelles raisons une machine à états correspond à votre cas d'usage, ces chapitres pourront être intéressants au moins pour les sujets variés qu'ils abordent: algorithmie, l'atomique, les problématiques.]]></summary></entry><entry><title type="html">The data compression (French)</title><link href="https://www.maybeuninit.com/2022/09/29/final-state.html" rel="alternate" type="text/html" title="The data compression (French)" /><published>2022-09-29T00:00:00+00:00</published><updated>2022-09-29T00:00:00+00:00</updated><id>https://www.maybeuninit.com/2022/09/29/final-state</id><content type="html" xml:base="https://www.maybeuninit.com/2022/09/29/final-state.html"><![CDATA[<h1 id="ma-quête-vers-la-compression">Ma quête vers la compression</h1>

<p><span style="color: #A0A0A0">[2022-09-29] #FSE #Algorithmie #Vie #Compression</span></p>

<hr />

<h2 id="preface---life-post">Preface - Life post</h2>

<p>Si vous désirez sauter cette introduction où je raconte ma vie, ce que je comprends très bien,
rendez-vous directement à la section
<a href="#les-algorithmes-de-compression---début-du-technique">Les algorithmes de compression - début du technique</a> !</p>

<p>Je me souviens avoir passé un entretien, un jour, ou j’ai dit que j’aimais bien
l’algorithmie. Tout s’est bien passé, mais à la fin de l’entrevue on m’a répondu:</p>

<blockquote>
  <p>“C’est bizarre, tu dis que tu aimes l’algo, mais tu fais ça de cette manière ?
Tout le monde sait que ça peut être résolu en O de N sur deux !”</p>
</blockquote>

<p>J’avais codé cette partie sans trop me questionner. Après tout, j’allais vite,
je n’ai pas pensé que justement, j’allais devoir optimiser ce bout là. Ça veut
dire que je n’aime pas l’algo ? Ou bien tout simplement que je suis éclaté ? Je
me posais ces questions, en plus dans une période de ma vie où je doutais un peu
de ma carrière. C’était carrément un coup au moral.</p>

<p>Comme tout informaticien ayant fait des études de programmation, j’ai implémenté
les classiques: des tris, des plus courts chemins, un allocateur, un alpha-beta
pruning… et j’en passe.</p>

<p>Mais même en connaissant mes classiques, je pourrais mettre un peu plus de cinq
minutes pour ressortir un A* parfait, sans ressource. Je ne m’exerce pas tous
les jours, et le monde de l’informatique est trop grand pour tout connaître, non
? Avec du recul, je sais aujourd’hui que cette partie en entretien n’a pas été
décisive. J’étais suffisamment junior pour que ça se voit, même en baratinant.</p>

<p>Un bon ami me dit souvent, “D’abord, implémente naïvement, ensuite réfléchis”.
Et je trouve ça plutôt juste. Lorsqu’on zone là où ça parle d’algo, on tombe
souvent sur quelque chose sans le vouloir. Si on est curieux, on apprend, on se
rend compte de nos erreurs, on s’améliore et nos codes deviennent meilleurs.
Mais le plus important est de s’amuser et de construire quelque chose.</p>

<h2 id="introduction">Introduction</h2>

<p>18 Janvier 2022. Je découvrais la série “Silicon Valley”, que je vous conseille
d’ailleurs. Sans vous en dire plus, je suis instantanément allé regarder ce qui
se faisait en matière de compression de données.</p>

<p>J’ai découvert un univers, là où moi j’en étais resté au <code class="language-plaintext highlighter-rouge">LZW</code>. Ce qui est
genial, c’est qu’il n’y a PAS de bonne solution. Chacun a son rôle à jouer. Et
si certaines méthodes ont des performances nettement plus sympas, ça ne signifie
pas qu’elles sont les plus adaptées pour toutes problématiques.</p>

<p>Ce n’est pas tout ! Les perforances dépendent aussi des capacités hardwares !
L’amélioration de nos CPUs nous permet d’exécuter des multiplications de
plus en plus vite. Les solutions de chiffrement arithmétique ont de plus en plus
leur mot à dire.</p>

<p>“Finite State Entropy”, basé sur les recherches de Jarek Duda il y a quelques
années, a vraiment titillé ma curiosité. Je n’étais pas au bout de mes peines.
Car, si trouver des infos sur des algos comme celui de Huffman, ou encore
Lempel-Ziv-Welch, est simple; trouver une explication abordable de FSE est <em>très
très</em> complexe. Réservé à l’élite des gens qui écoutaient vraiment en cours de
master d’info.</p>

<h2 id="zstd---lenrôlement">Zstd - L’enrôlement</h2>

<p>J’ai commencé par passer beaucoup de temps sur le répo de zstd de Facebook. Il
se trouve que FSE est libre de droits, et que zstd est open source. Et il possède
parmi d’autres une implementation à laquelle Yann Collet a participé.</p>

<p>Comprendre par le code a souvent fonctionné chez moi. Et même si ça faisait
quelques années où je n’avais pas fait du C. J’en ai quand même tiré certains
éléments importants qui seront utilisés plus tard.</p>

<p>À propos du C:</p>

<p>Étudier l’informatique grâce à ce langage est exceptionnel. Mais le C a ses
défauts, et le manque de lisibilité en est un. Le code du FSE est super, il est
optimal pour beaucoup de points de vu. La norme actuelle est plutôt d’utiliser
de la monomorphisation dans une bibliothèque, ce que le C ne permet pas facilement. En bref, une implémentation dans un autre langage ne pourrait qu’amener du positif.</p>

<p>Outre le langage, sans connaître les enjeux de FSE, on fait une drôle de tête
devant des fonctions comme celle de normalisation. Pleines de choix techniques et
d’optimisations à partir de preuves mathématiques. Sans doute pour des
performances exceptionnelles, mais trop difficile à prendre en main.</p>

<p>Finalement, si je voulais comprendre FSE, ce n’était une bonne idée. Mais j’ai
appris des choses, sur du langage C et de la culture G d’informaticien. C’est un
travail qui peut être décourageant, sembler ne servir à rien, mais qui n’ait
jamais une perte de temps.</p>

<h2 id="les-algorithmes-de-compression---début-du-technique">Les algorithmes de compression - début du technique</h2>

<p>Il y a deux grandes familles d’algorithmes de compression. On les connaît bien,
ce sont les “sans perte” et “avec perte”. Ici, on s’interesse aux “sans perte”,
pour vous citer quelques noms: LZ4, LZW, FSE, ZIP, etc.</p>

<p>Une bonne partie des algos utilisent des tables de compression, et d’autres non.
Pour moi, les deux grandes familles sont: <strong>TABLE</strong> ou <strong>ARITHMETIQUE</strong>.</p>

<h2 id="chapitre-1-les-tables-de-compressions---ouverture-dune-parenthèse">Chapitre 1, les tables de compressions - ouverture d’une parenthèse</h2>

<p>Utiliser une “table de compression” signifie que pour un symbole, on associe une
valeur.</p>

<p>Il y a plusieurs façons de construire ce genre de table.</p>

<p>En résumé, un symbole de taille 16, qui sort le plus souvent, sera remplacé par
un autre symbole de taille 1. Le reste sera substitué par des symboles plus
gros. L’objectif est que, même avec une répartition équitable des symboles, on
gagne déjà de la place. Ça dépendra de la taille de l’alphabet aussi bien sûr.</p>

<p>En résumé, on associe des symboles qui, seront des lettres, à des séquences
de 0 et de 1 qui seront des bits. Généralement, une lettre tient
sur 8 bits avant la compression.</p>

<p>Si dans notre table on décide que A sera remplacé par ‘0001’, et B par ‘1’. Si B
est moins fréquent que A, on n’aura pas une superbe compression. La répartition
des symboles est très importante pour une bonne performance.</p>

<p>L’utilisation de la même méthode de compression, avec des alphabets constitués de
différents symboles, aura un résultat différent tandis que la source restera identique.
Par exemple pour “ABAAACABAA”, une construction d’alphabet pourrait être
“A”, “B”, “C”. Ou alors “AB”, “AA”, “AC”. Le choix impactera les performances.</p>

<p>Zip, par exemple utilise une méthode du type Encodage de Huffman, avec une table
de compression. Compresser 2 fichiers zip, peut à nouveau avoir une plus petite
taille. Car les alphabets peuvent être différents. On peut aussi obtenir des
résultats différents en compressant le contenu de 2 fichiers zip simultanément,
ou en compressant les zips eux-même.</p>

<p>Ces tables sont très pratiques pour la décompression. Pas d’opérations
gourmandes en CPU, on remplace des bits par un symbole. Recherche rapide,
écriture rapide. Par contre la construction de la table est assez lente.</p>

<p>Avec une table, on peut facilement encoder et décoder “simultanément” dans le
style fifo. C’est super pour de la communication réseau. Suffisamment efficace
pour des petits alphabets. En plus les algorithmes sont sur Wikipédia. Comme je
vous le disais, trouver des informations sur ces différentes méthodes: c’est
facile !</p>

<h2 id="chapitre-2-les-compressions-arithmétiques-je-donne-un-exemple">Chapitre 2, les compressions arithmétiques, je donne un exemple</h2>

<div class="tex2jax_ignore">
Avec la compression (code) arithmétique, on utilise des maths. Sans surprise ?
Depuis quelques années, nos CPU deviennent de plus en plus performants.
Exécuter des opérations telles que des multiplications deviennent de plus en
plus rapides. On voit évoluer, pour les mêmes exécutions, l'efficacité des
méthodes utilisant du calcul.
</div>

<p>Si la l’utilisation d’une table ressemblait à $symbole \implies bits$, le codage
arithmétique ressemble plus à $(état, symbole) \implies état$. En bref, on
construit une machine à état.</p>

<p>Prenons une séquence de charactères. <code class="language-plaintext highlighter-rouge">ABADABAC</code>.</p>

<p>Dans notre exemple, on a 4xA, 2xB, 1xC,
1xD, 8 caractères au total. Donc les probabilites $P(A) = \frac{1}{2}$,
$P(B) = \frac{1}{4}$, $P(C) = P(D) = \frac{1}{8}$.</p>

<p>Prenons un segment de taille 1. On place $a$ d’un coté et $b$ de l’autre, tel
que $a = 0$ et $b = 1$. On y ajoute des repères correspondant aux probabilités
des symboles. On attribut un symbole a tout ce qui se trouve entre ces repères. Le
segment à gauche du repère A représente le symbole A, le à gauche du repère B et
à droite A représente le symbole B, etc.</p>

<p>Voila a quoi ca ressemble:</p>

<p><img src="/assets/img/aritm1.png" alt="My Image" /></p>

<p>Maintenant, cherchons à encoder le premier symbole de la séquence “ABADABAC”.
Pour notre algorithme de compression, on doit remettre à l’échelle les valeurs
de <code class="language-plaintext highlighter-rouge">a</code> et de <code class="language-plaintext highlighter-rouge">b</code>.</p>

<p><code class="language-plaintext highlighter-rouge">a</code> devient la valeur basse de $P(A)$, et <code class="language-plaintext highlighter-rouge">b</code> la valeur haute de $P(A)$. Puis, entre
<code class="language-plaintext highlighter-rouge">a</code> et <code class="language-plaintext highlighter-rouge">b</code>, on redispose les repères. Avant, on était à une echelle 1 $(b - a = 1)$,
maintenant on est à une échelle de 0,5. Alors notre segment ressemble à ça:</p>

<p><img src="/assets/img/aritm3.png" alt="My Image" /></p>

<p>Voilà, on répéte la même chose jusqu’à la fin. Pour le faire efficacement, on a
besoin de deux choses:</p>

<ol>
  <li>
    <p>Une <a href="https://en.wikipedia.org/wiki/Cumulative_distribution_function">fonction
cumulative</a>,
permet de savoir où le sous-segment d’un symbole commence.</p>

    <p>On veut diviser le segment. Avec $P(A, B, C, D) = (0.5, 0.25, 0.125, 0.125)$.
Calculer la CDF nous donne $c(A, B, C, D) = (0, 0.5, 0.75, 0.875)$, les
<em>valeurs basses des sous-segments</em>.</p>
  </li>
  <li>
    <p>Un cumul de la distribution ou la fréquence et de la fonction cumulative pour savoir où le
symbole finit.</p>

    <p>$d(A, B, C, D) = (c(A) + P(A), …, c(D) + P(D)) = (0.5, 0.75, 0.875, 1)$ ce qui
nous donne les <em>valeurs hautes des sous-segments</em>.</p>
  </li>
</ol>

<p>Remettre à l’échelle veux dire $a := a + (b - a) * c(x)$,
$x$ est le caractère courrant à encoder $\in {A, B, C, D}$.
Notez qu’on utilise $c(x)$ car on cherche <em>la valeur basse</em>.
Et suivant le même principe, devient $b := a + (b - a) * d(x)$`.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>a = 0, b = 1
pour chaque c dans "ABADABAC"
    w = b - a
    b = a + w * d[c]
    a = a + w * c[c]
</code></pre></div></div>

<p>Je bricole un petit bout de code à partir de ça et je trouve l’intervalle
$[a, b)$ sans me casser la tête: $[0.3070068359375, 0.30706787109375)$.
Et voilà, cet intervalle c’est notre état final. À lui seul il représente
toute notre séquence encodé.</p>

<blockquote>
  <p>Ce qu’il faut à cette étape, c’est imaginer qu’on zoom vers la section qui
représente notre symbole. Puis on remet sur cette nouvelle échelle des
sections pour tous nos symboles. Un zoom égal un état, et l’état final sont
les derniers $a$ et $b$.</p>
</blockquote>

<p>Maintenant qu’on a l’intervalle, on peut produire une séquence binaire
correspondante. Comment qu’on peut faire pour représenter un chiffre à virgule
en dessous de 0 ?</p>

<p>En fait c’est assez simple. Si dans le monde décimal
$0.1 = \frac{1}{10}$
et
$0.11 = \frac{1}{10^1} + \frac{1}{10^2}$.
En binaire ca pourrait etre $.1_{b} = \frac{1}{2}$ <span>
, $.11_{b} = \frac{1}{2^1} + \frac{1}{2^2}$
</span></p>

<p>…ou encore
$.101_{b} = \frac{1}{2} + \frac{0}{2^2} + \frac{1}{2^3}$</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-- Phase 1
tant que a &gt; 1/2 ou b &lt; 1/2
    si b &lt; 1/2
        produire 0
        a := 2a
        b := 2b
    sinon si a &gt; 1/2
        produire 1
        a := 2(a - 1/2)
        b := 2(b - 1/2)

-- Phase 2
s = 0
tant que a &gt; 1/4 et b &lt; 3/4
    s := s + 1
    a := 2(a - 1/4)
    b := 2(b - 1/4)
s := s + 1

-- Phase 3
si a &lt;= 1/4
    produire 0
    produire s fois 1
sinon
    produire 1
    produire s fois 0
</code></pre></div></div>

<p>Pas de panique, je vous explique ce qui se passe. Souvenez-vous de ce segment,
on avait avec $a$ et $b$. Découpons ce segment en 2, à gauche on dit que c’est
0, à droite 1. On choisit la partie où se trouve notre intervalle. Entre 0 et
0.5, donc sur la partie de 0. Puis on double a et b. Eh oui on double ! Car
l’intervalle diminue de moitié et l’échelle grandie !</p>

<p>On reproduit cette étape, plusieurs fois, jusqu’à ce que l’intervalle chevauche
la partie gauche ET la partie droite. C’était la phase 1. À ce stade, il ne faut
pas diviser le segment par deux, mais par quatre. Un schéma vaut mieux qu’un millier
d’explications.</p>

<p><img src="/assets/img/aritm4.png" alt="Retrouver les bits" /></p>

<p>Puis observez attentivement. Vous remarquez que <code class="language-plaintext highlighter-rouge">a</code> commence par chevaucher
‘01’, puis ‘011’. Ce n’est pas pour rien. La tendance de l’intervalle penche
plus vers la gauche, et donc naturellement, plus l’echelle grandie, plus <code class="language-plaintext highlighter-rouge">a</code> se
rapproche de la limite gauche. Plus rapidement que <code class="language-plaintext highlighter-rouge">b</code> vers 1.</p>

<p>Un autre intervalle aura prefere tendre vers la partie droite. Les bits produit
par cette phase ressemblent soit a ‘01111…’ soit a ‘1000…’ Et que le nombre
de 0 ou de 1 correspond quasiment au nombre d’iterations dans la phase 2.</p>

<p>En résumé, la phase 3 construit les chaines, 0111… ou 1000… en fonction de
si on tendait vers $a == 0$, ou $b == 1$.</p>

<p>Bon, il se trouve qu’avec notre répartition étrange on finit toujours avec
$a = 0.5$ et $b = 0.75$ a la fin de notre première etape, et donc on produit ‘10’ en
fin d’algo.</p>

<p>Et j’obtiens la séquence $01001110100110_b=0.3070068359375$ appartenant
à l’intervalle qu’on avait trouvé.</p>

<h2 id="décoder-un-encodage-arithmétique">Décoder un encodage arithmétique</h2>

<p>Pour décoder, on reprend le premier pseudocode et on rajoute un test pour
savoir quel symbole émettre.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">a</span> <span class="o">=</span> <span class="mf">0f64</span><span class="p">;</span>
<span class="k">let</span> <span class="k">mut</span> <span class="n">b</span> <span class="o">=</span> <span class="mf">1f64</span><span class="p">;</span>

<span class="c1">// J'ai explique un peu plus haut comment faire, je reviendrais en</span>
<span class="c1">// detail dessus dans un autre post.</span>
<span class="k">let</span> <span class="n">z</span> <span class="o">=</span> <span class="nf">bin_to_float</span><span class="p">(</span><span class="n">out</span><span class="p">);</span>
<span class="k">loop</span> <span class="p">{</span>
    <span class="k">for</span> <span class="n">n</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">p</span><span class="nf">.len</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">w</span> <span class="o">=</span> <span class="n">b</span> <span class="o">-</span> <span class="n">a</span><span class="p">;</span>
        <span class="k">let</span> <span class="n">b0</span> <span class="o">=</span> <span class="n">a</span> <span class="o">+</span> <span class="n">w</span> <span class="o">*</span> <span class="n">d</span><span class="p">[</span><span class="n">n</span><span class="p">];</span>
        <span class="k">let</span> <span class="n">a0</span> <span class="o">=</span> <span class="n">a</span> <span class="o">+</span> <span class="n">w</span> <span class="o">*</span> <span class="n">c</span><span class="p">[</span><span class="n">n</span><span class="p">];</span>
        <span class="k">if</span> <span class="n">a0</span> <span class="o">&lt;=</span> <span class="n">z</span> <span class="o">&amp;&amp;</span> <span class="n">z</span> <span class="o">&lt;</span> <span class="n">b0</span> <span class="p">{</span>
            <span class="nd">print!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span> <span class="n">index_symbol</span><span class="p">[</span><span class="n">n</span><span class="p">]);</span>
            <span class="n">a</span> <span class="o">=</span> <span class="n">a0</span><span class="p">;</span>
            <span class="n">b</span> <span class="o">=</span> <span class="n">b0</span><span class="p">;</span>
            <span class="c1">// personellement j'ai mis C comme EOF</span>
            <span class="k">if</span> <span class="n">index_symbol</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'C'</span> <span class="p">{</span>
                <span class="k">return</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="fin-de-la-parenthèse">Fin de la parenthèse</h2>

<p>On peut dire de nombreuses choses en plus sur ce système d’encodage. Déjà,
comment gère-t-on l’imprécision du CPU ? On ne peut pas avoir une précision
infinie, et une séquence du taille raisonnable dépasserait les limite imposée
par la technologie. Ce n’est pas tellement une mauvaise idée d’encoder une
source morceau par morceau a priori, mais ça demande réflexion.</p>

<div class="tex2jax_ignore">
Vous remarquerez que la complexitée algorithmique pour encoder est faible, `O(n)`.
C'est un point positif, car ça ne varie pas en fonction de l'ordre de mon histogramme.
Pendant qu'un Huffman s'execute en `O(nlog n)` avec un histogramme non trié.
</div>

<blockquote>
  <p>“Même dans un Âge mythique, il doit y avoir des énigmes, comme il y en a toujours”</p>

  <div style="text-align: right; margin: 0 15px;">- Tolkien</div>
</blockquote>

<p>Avez-vous essayé de compresser cette séquence, avec l’algorithme de Huffman ?
Vous ne remarquez pas quelque chose ? Qu’est-ce que vous en déduisiez ?</p>

<p>J’aimerais vraiment en apprendre plus sur le sujet. Notamment autour des
comparaisons avec Huffman ! Ainsi qu’implémenter de nouveau LZW, Huffman et un
codage arithmétique scalable. Je souhaitais mettre à jour mes connaissances en
compressions, et c’est chose faite. J’espère que cette parenthèse vous aura
aussi plu.</p>

<h2 id="chapitre-3---ans-cest-quoi-cest-quoi-">Chapitre 3 - ANS, c’est quoi c’est quoi ?</h2>

<p>FSE est une implementation qui utilise un système numérique asynchrone ! Vous
n’aviez pas encore compris ?</p>

<p>De la meme facon que le codage arithmetique, cette methode est plutot de type
$(symbole, etat) \implies (etat)$.</p>

<p>Le mieux c’est de commencer par un exemple. Pour FSE, on a besoin d’un histogram
des symboles dans la source qu’on cherche a compresser. Par exemple, dans
<code class="language-plaintext highlighter-rouge">ABADABACA</code> notre histogram sera <code class="language-plaintext highlighter-rouge">[4, 2, 1, 1]</code> correspondant respectivement au
symbols <code class="language-plaintext highlighter-rouge">[A, B, C, D]</code>. L’ordre n’importe pas notre logique, on aurrait tres
bien pu construire notre histogram <code class="language-plaintext highlighter-rouge">[2, 1, 4, 1]</code> correspondant a <code class="language-plaintext highlighter-rouge">[B, C, A,
D]</code>.</p>

<p>Je commence par calculer la somme cumulative telle que $cdf_i = cdf_{i - 1} +
hist_i$ et $cdf_0 = 0$. Je reviendrai dessus plus tard, mais le maximum de ma
somme doit absoluement être une puissance de 2, heureusement dans notre cas on a
rien a faire car $\sum hist_i = 2^3$.</p>

<p>Imaginez que vous deviez construire un tableau dans lequel vous listeriez des
états qui iraient de 0 jusqu’à l’infinie. Pour chacun de ces états, vous y
associez un symbole. Vous savez que <code class="language-plaintext highlighter-rouge">A</code> aura 2 fois plus d’états que <code class="language-plaintext highlighter-rouge">B</code>, qui en
aura deux fois plus que <code class="language-plaintext highlighter-rouge">C</code> ou <code class="language-plaintext highlighter-rouge">D</code>.</p>

<h2 id="la-normalisation---étape-majeure-de-lans">La normalisation - étape majeure de l’ANS</h2>

<p>Construisons le même segment que tout a l’heure. Chaque partie correspond au
pourcentage de chance de tomber sur un symbole A, B, C ou d. La première étape
sera de s’assurer d’une chose à propos de cette distribution: Il faut que la
somme de nos fréquences tienne sur une puissance de 2, la plus basse possible de
préférence.</p>

<p>Si je reprends la chaine <code class="language-plaintext highlighter-rouge">ABADABAC</code>, les fréquences étaient de 4, 2, 1 et 1. Ce
qui nous donne 8 ou $2^3$. C’est un peu trop simple, le calcul est déjà fait.
Imaginons qu’on ait une chaine avec des fréquences telles que
$freq(A, B, C, D) = (42, 23, 10, 11)$.
Pour avoir une jolie répartition, il faut appliquer une normalisation.</p>

<p>Personnellement, j’en ai implémenté une très simple. Cette implem est loin
d’être <em>l’Unique</em> ! Je vous laisse la liberté d’en proposer de nouvelles. Voire,
d’essayer de comprendre celle de Facebook, hein, on ne sait pas hein, elle est
peut-être un peu élaborée. Si l’occasion se présente, envoyez-moi vos progrès,
j’y trouverai un grand intérêt.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">simple_normalization</span><span class="p">(</span>
    <span class="n">histogram</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">usize</span><span class="p">],</span>
    <span class="n">cdf</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">usize</span><span class="p">],</span>
    <span class="n">table_log</span><span class="p">:</span> <span class="nb">usize</span>
<span class="p">)</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">previous</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">let</span> <span class="n">max</span> <span class="o">=</span> <span class="o">*</span><span class="n">cdf</span><span class="nf">.last</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">();</span>
    <span class="k">let</span> <span class="n">target_range</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="n">table_log</span><span class="p">;</span> <span class="c1">// 2 ^ table_log</span>
    <span class="k">let</span> <span class="n">actual_range</span> <span class="o">=</span> <span class="n">max</span><span class="p">;</span>

    <span class="n">cdf</span><span class="nf">.iter_mut</span><span class="p">()</span><span class="nf">.enumerate</span><span class="p">()</span><span class="nf">.skip</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="nf">.for_each</span><span class="p">(|(</span><span class="n">i</span><span class="p">,</span> <span class="n">c</span><span class="p">)|</span> <span class="p">{</span>
        <span class="o">*</span><span class="n">c</span> <span class="o">=</span> <span class="p">(</span><span class="n">target_range</span> <span class="o">*</span> <span class="p">(</span><span class="o">*</span><span class="n">c</span><span class="p">))</span> <span class="o">/</span> <span class="n">actual_range</span><span class="p">;</span>
        <span class="k">if</span> <span class="o">*</span><span class="n">c</span> <span class="o">&lt;=</span> <span class="n">previous</span> <span class="p">{</span>
            <span class="nd">panic!</span><span class="p">(</span><span class="s">"table log too low"</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="n">histogram</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="o">*</span><span class="n">c</span> <span class="o">-</span> <span class="n">previous</span><span class="p">;</span>
        <span class="n">previous</span> <span class="o">=</span> <span class="o">*</span><span class="n">c</span><span class="p">;</span>
    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>J’utilise pour la première fois le concept de <code class="language-plaintext highlighter-rouge">table_log</code>. Cette variable, à
part le fait qu’on dise qu’on doit s’aligner sur $2^{tableLog}$, a un réel
impact sur la compression. Elle joue le rôle de <em>potentiomètre</em> concernant la
vitesse d’exécution <strong>et</strong> la qualité de compression. Une <code class="language-plaintext highlighter-rouge">table_log</code> élevée
tendra à augmenter la précision de la normalisation. Il y aura moins de <code class="language-plaintext highlighter-rouge">1</code> dans
l’histogramme. Cependant, augmenter cette variable va aussi nuire à
l’algorithme. Jusqu’à finir par donner une sortie plus grande que l’entrée.
Baisser cette valeur a aussi un bon impact sur la vitesse d’exécution. Ça permet
d’arriver moins vite à des états élevés qui prennent plus de temps de CPU pour
être traités, et d’éviter des calculs superflus, on verra ça plus tard. En revanche,
utiliser une valeur trop basse peut nuire à notre normalisation en la rendant
impossible à réaliser, il faut trouver le juste équilibre.</p>

<ol>
  <li>
    <p>Je calcule la fonction cumulative de mon histogramme. Mon histogramme, c’est
simplement une liste de fréquences. J’applique la <em>CDF</em>, tel que $cdf_i =
cdf_{i - 1} + freq_i$ et $cdf_0 = 0$. En suivant mon exemple, je trouve $max
= 90$. J’aimerais transposer chaque valeur depuis l’échelle $[0, 90]$, sur
l’intervalle $[0, 2^3]$.</p>
  </li>
  <li>
    <p>J’applique un <a href="https://en.wikipedia.org/wiki/Linear_map">mapping</a>. Vu que l’histogramme est la dérivée de ma fonction cumulative, je peux retrouver la valeur de mon histogramme à la position $i - 1$ en soustrayant <code class="language-plaintext highlighter-rouge">previous</code> de <code class="language-plaintext highlighter-rouge">c</code>. Avec ce code je devrais pouvoir retrouver $freq_{norm}(A, B, C, D) = (4, 2, 1, 1)$ avec une <code class="language-plaintext highlighter-rouge">table_log</code> de 3.</p>
  </li>
</ol>

<blockquote>
  <p>Le fait de devoir s’aligner sur une puissance de 2 selon moi devrait être optionnel.
Ça nous permet d’accélérer l’algorithme, oui, car les multiplications peuvent
facilement être remplacées par des shifts $\times{8} \iff \ll{3}$. Par contre,
c’est un overhead à la compréhension de ce que <strong>fait</strong> l’algo, donc ça nuit un peu
à notre expérience.</p>

  <p>J’ai préféré ne pas retirer le concept. Étant donné que c’est quand même une
partie importante. En contre-partie, je vous aiderai au moment
où je considérerai qu’un petit coup de pouce est nécessaire.</p>
</blockquote>

<h2 id="les-états-de-lans---comment-ça-marche-alors-">Les états de l’ANS - comment ça marche alors ?!?</h2>

<p>Reprenons après la normalisation. On a nos fréquences, on peut construire un
segment de taille $\sum_{i}{freq_i}$. Maintenant, je prosose de répéter ce
segment à l’infini, comme ci-dessous, et de nous poser une petite question.</p>

<p><img src="/assets/img/fse_ex.png" alt="FSE, extension de la table" /></p>

<p>Pour commencer, je tire nombre $x$ entre 0 et 3, je tombe sur A. Entre 4 et 5, B; 6, C; 7, D.
Si je tire un nombre entre 8 et 15, je devrais avoir une repartition similaire à celle entre 0 et 7.
Vu que la première répartition se répète infiniement, je peux comprendre sur laquelle je suis
en divisant mon nombre aléatoire par la somme des frequences $floor(x/8)$ qu’on note $\lfloor x/8 \rfloor$.</p>

<p>Déjà je sais si je suis sur genre X’, X’’, etc.
Maintenant pour retrouver exactement sur quel symbole
je suis, c’est plus compliqué. Il faut que je trouve le symbole pour lequel le
cdf est le plus grand et
$cdf(symbol) \leq x$. Cette recherche se fait généralement en
<span class="tex2jax_ignore"><code class="language-plaintext highlighter-rouge">O(n log(n))</code></span>
cependant, avec un alphabet d’une taille raisonnable, la <code class="language-plaintext highlighter-rouge">méthode des alias</code>
est envisageable pour
une recherche en <span class="tex2jax_ignore"><code class="language-plaintext highlighter-rouge">O(1)</code></span>.</p>

<p>Ce nombre <code class="language-plaintext highlighter-rouge">x</code> c’est notre état. Le principe de l’ANS nous propose un modèle qui
nous permettra de trouver à partir de <code class="language-plaintext highlighter-rouge">x</code> l’état précédent, et en fonction du
nouveau symbole, l’état suivant. Pour bien comprendre comment ça marche, il
faudrait d’abord représenter une table d’état.</p>

<p>Dans un tableau, notez pour chaque <code class="language-plaintext highlighter-rouge">x</code> de 0 à l’infini, un symbole et son index.
Vous pensez bien qu’on ne va pas réellement allouer une infinité d’états. Ce ne
serait pas top en compression et je suis sûr que ce n’est pas tout à fait
possible non plus avec nos techniques. Mais imaginez quand même:</p>

<p><img src="/assets/img/fse2.png" alt="Symbole + Index + État" /></p>

<h2 id="encoder-avec-ans---version-facile">Encoder avec ANS - version facile</h2>

<p>Disons que je suis à l’état 1, mon symbole actuel c’est A. Je cherche à encoder
le symbole B, je dois trouver le prochain état correspondant. Je récupère la
fréquence de B, que je divise par mon état actuel pour trouver le segment sur
lequel je vais aller. Eh oui, car par segment, d’après ma répartition, j’ai
$freq(B)$ symbole B.</p>

<p>Pour l’instant, je connais le segment, je connais aussi la taille du segment, 8.
Je peux savoir grâce à ces deux informations que mon prochain état sera entre $n
\times 8$ et $n\times(8+1)$. Maintenant quelle valeur exactement ça sera ?</p>

<p>Avec $cdf(B)$ je sais que mon premier symbole B sera à $n\times{8} + 4$. Mais je
dois connaitre lequel des 2 B correspond à A en tant qu’état précédent ! C’est
ça la magie ! Ma première division $n=\lfloor état/freq(B) \rfloor$ me donne le
segment suivant sur lequel je peux trouver un B correspondant à plusieurs états,
dont mon état actuel ! Pour le retrouver, il suffit d’ajouter l’état modulo la
fréquence.</p>

<p>Pas facile à suivre, voici l’équation finale:</p>

<p>$NouvelEtat(Symbol, Etat)=\lfloor \frac{Etat}{freq(Symbol)} \rfloor \times totalFreqs + cdf(Symbol) + Etat \% freq(Symbol)$</p>

<blockquote>
  <p>Ici le fait d’être aligné sur une puissance de 2 nous permet de remplacer $\times{totalFreqs}$
par un shift. Le total est égal à $2^{tableLog}$ d’où
$n \times{totalFreqs} \iff n \ll{tableLog}$</p>
</blockquote>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">not_scalable_encode</span><span class="p">(</span>
    <span class="n">frequencies</span><span class="p">:</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="p">[</span><span class="nb">usize</span><span class="p">],</span>
    <span class="c1">// symbol_index me permet de retrouver l'index où je stocke</span>
    <span class="c1">// la fréquence et la cdf pour un symbole. Utiliser des</span>
    <span class="c1">// vecteurs, c'est pratique mais ça a aussi cet inconvénient.</span>
    <span class="n">symbol_index</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">HashMap</span><span class="o">&lt;</span><span class="nb">u16</span><span class="p">,</span> <span class="nb">usize</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="n">table_log</span><span class="p">:</span> <span class="nb">usize</span><span class="p">,</span>
    <span class="n">src</span><span class="p">:</span> <span class="o">&amp;</span><span class="p">[</span><span class="nb">u16</span><span class="p">],</span>
<span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">usize</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">cs</span> <span class="o">=</span> <span class="nf">build_cumulative_symbol_frequency</span><span class="p">(</span><span class="n">frequencies</span><span class="p">);</span>
    <span class="nf">simple_normalization</span><span class="p">(</span><span class="n">frequencies</span><span class="p">,</span> <span class="o">&amp;</span><span class="k">mut</span> <span class="n">cs</span><span class="p">,</span> <span class="n">table_log</span><span class="p">);</span>
    <span class="c1">// Je commence arbitrairement à 1 pour mon exemple, mais le choix</span>
    <span class="c1">// de l'état initial peut être important.</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">state</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">src</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.for_each</span><span class="p">(|</span><span class="n">symbol</span><span class="p">|</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">index</span> <span class="o">=</span> <span class="o">*</span><span class="n">symbol_index</span><span class="nf">.get</span><span class="p">(</span><span class="n">symbol</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>
        <span class="k">let</span> <span class="n">fs</span> <span class="o">=</span> <span class="o">*</span><span class="n">frequencies</span><span class="nf">.get</span><span class="p">(</span><span class="n">index</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>
        <span class="c1">// (floor(state / frequency) &lt;&lt; table_log) + (state % frequency) + cumul</span>
        <span class="n">state</span> <span class="o">=</span> <span class="nf">compress</span><span class="p">(</span><span class="n">state</span><span class="p">,</span> <span class="n">table_log</span><span class="p">,</span> <span class="n">fs</span><span class="p">,</span> <span class="o">*</span><span class="n">cs</span><span class="nf">.get</span><span class="p">(</span><span class="n">index</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">());</span>
    <span class="p">});</span>
    <span class="n">state</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Voici un peu de code qui nous montrent qu’encoder reste vraiment très simple. Je
me doute que vous comprenez pourquoi ce n’est pas possible d’utiliser
sérieusement ce code en production. Mais au cas où je vous donne un indice.
<code class="language-plaintext highlighter-rouge">state</code> ne pourrait-il pas devenir un peu grand à force ?</p>

<h2 id="decoder---encore-la-version-facile">Decoder - encore la version facile</h2>

<p>Je pense que maintenant il faut commencer par un exemple visuel. Imaginons qu’avec
le code précédent, j’ai compréssé la séquence <code class="language-plaintext highlighter-rouge">ABA</code> avec mon alphabet. Mon code me
donnais l’état <code class="language-plaintext highlighter-rouge">9</code>.</p>

<p><img src="/assets/img/fsedec.png" alt="FSE decodage facile" /></p>

<p>L’idée c’est que grâce à mon état, je retrouve l’état précédent avec plus ou
moins les mêmes calcules que pour encoder. Je retrouve mon symbole actuel, pour
pouvoir connaitre la fréquence et la somme cumulative à partir desquelles
j’avais trouvé mon état à l’époque. Vous voyez la formule suivante fait
exactement la même chose que pour encoder mais dans le sens inverse:</p>

<p>$Précédent(Etat)=freq(Symbol)\times \lfloor \frac{Etat}{totalFreqs} \rfloor + Etat \% total_freq - cdf(Symbol)$</p>

<p>Je vous laisse essayer, normalement vous devriez faire le même cheminement que
moi. Si vous en faites un autre, demandez-vous si vous utilisez le bon symbole
pour chercher la fréquence et la somme cumulative. Si vous n’y arrivez toujours
pas, demandez-vous si vous savez bien calculer ?</p>

<h2 id="à-propos-de-de-létat-initial">À propos de de l’état initial</h2>

<p>Dans mon exemple d’encodage, je vous disais que bien choisir l’état initial peut
être important. Pour montrer pourquoi, mettons nous dans la situation où A est
le premier symbole que je veux encoder, puis choisissons 0 comme état initial.</p>

<p>Pour rappel, l’équation qui me sert à trouver mon état suivant est:</p>

<p>$e´(s, e)=\lfloor \frac{e}{freq(s)} \rfloor \times t + cdf(s) + s \% freq(s)$</p>

<p>Si vous ne comprenez rien, je vous invite à remonter de deux chapitres. En
attendant, voyons ce qu’$e´(A, 0)$ vaut… 0 ? Ok… $e´ = e$… Et c’est pareil
pour tous mes autres symboles si je prends leurs états respectifs sur le premier
segment. Eh oui.</p>

<p>Une tech’ pour choisir l’état initial serait de le piquer sur le second segment.
De cette manière vous admettez que finir sur un état dans l’intervalle du
premier segment est un signal de fin de decompression.Les mêmes solutions que
celles de l’encodage arithmétique fonctionnent aussi. Par exemple, si on
commence à l’état d’un EOF on va forcément avoir un état différent pour le
symbole suivant. Une taille aussi devrait fonctionner.</p>

<p>On peut aussi faire les malins. On affirme que notre chaine commencera par A
suivi d’un symbole différent. Ce n’est pas très élégant, mais efficace. À vous
de voir la méthode que vous préférez. J’avoue, j’ai un peu fait ça.</p>

<h2 id="chapitre-4---dernière-ligne-droite-rendre-tout-ça-compliqué">Chapitre 4 - Dernière ligne droite, rendre tout ça compliqué</h2>

<p>Vous avez dû remarquer qu’avec cette méthode, l’état final risque d’être très
très grand. Il risque même très fortement d’être trop grand pour votre
ordinateur. C’est pourquoi vous devriez limiter la taille de votre état à un
intervalle supportable. Pourquoi pas dans l’intervalle $[2^{16}, 2^{32}]$ ? Bien sûr
vous pouvez choisir cet intervalle en fonction de votre hardware.</p>

<p>Finalement, c’est simple. Vous prenez votre état, vous verifiez s’il n’est pas
superieur à la frequence, multiplié par 2 puissance X - table_log. Dans ce cas,
je shift l’état et j’écris dans un stream ce que je viens de shifter pour le
relire plus tard.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="n">d</span> <span class="o">=</span> <span class="mi">32</span> <span class="o">-</span> <span class="n">table_log</span><span class="p">;</span>
<span class="k">let</span> <span class="n">msk</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span> <span class="o">&lt;&lt;</span> <span class="mi">16</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// 2^16 - 1</span>

<span class="k">if</span> <span class="n">state</span> <span class="o">&gt;=</span> <span class="p">(</span><span class="n">fs</span> <span class="o">&lt;&lt;</span> <span class="n">d</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// On recupere les 16 premiers bits</span>
    <span class="c1">// de l'etat actuelle et on la stoque dans un</span>
    <span class="c1">// stream. On shift l'etat de 16 pour guarder</span>
    <span class="c1">// seulement les 16 bits plus grands.</span>
    <span class="k">let</span> <span class="n">bits</span> <span class="o">=</span> <span class="n">state</span> <span class="o">&amp;</span> <span class="n">msk</span><span class="p">;</span>
    <span class="k">let</span> <span class="n">nb_bits</span> <span class="o">=</span> <span class="nn">u64</span><span class="p">::</span><span class="n">BITS</span> <span class="o">-</span> <span class="n">bits</span><span class="nf">.leading_zeros</span><span class="p">();</span>
    <span class="n">estream</span><span class="nf">.unchecked_write</span><span class="p">(</span><span class="n">bits</span><span class="p">,</span> <span class="n">nb_bits</span><span class="nf">.try_into</span><span class="p">()</span><span class="nf">.unwrap</span><span class="p">());</span>
    <span class="n">nb_bits_table</span><span class="nf">.push</span><span class="p">(</span><span class="n">nb_bits</span><span class="p">);</span>
    <span class="n">state</span> <span class="o">&gt;&gt;=</span> <span class="mi">16</span><span class="p">;</span>
<span class="p">};</span>

<span class="c1">// .. encoder avec le nouvel état</span>
</code></pre></div></div>

<p>On peut se demander pourquoi ce test <code class="language-plaintext highlighter-rouge">state &gt;= (fs &lt;&lt; d)</code> nous permet de s’assurer de ne pas dépasser 32 bits. Pourquoi pas simplement shifter après l’encodage ? Et bien parce qu’on est capable de savoir si on va dépasser ou non en fonction de la fréquence.</p>

<p>Déjà, on remarque que pour toutes fréquences dans l’histogramme, on ne dépassera
jamais 2^32. C’est dû à la normalisation qu’on a appliquée précédemment. De
plus, dans certains cas, encoder un symbole avec une fréquence élevée nous fera
passer cette étape, alors que d’autres fréquences demanderont un shift.</p>

<p>$e´(s, e)=\lfloor \frac{e}{freq(s)} \rfloor \times t + cdf(s) + s \% freq(s)$</p>

<p>Si on prend notre exemple de fréquences avec $f_A = 4$ et $f_C = 1$, on se rend compte que $e´(A, e) \times{4} \approx e´(C, e)$ avec <code class="language-plaintext highlighter-rouge">t</code> une puissance de 2. De plus on se rend compte que $f_A = f_C \times{4}$. Pour être tout à fait honnête, je doute encore de mon raisonnement. Mais si mon état est inférieur à ma fréquence shiftée de <code class="language-plaintext highlighter-rouge">32 - table_log</code>, il n’y a aucune raison que mon prochain état dépasse les 32 bits.</p>

<p>Pour décoder, c’est exactement l’inverse. J’ajoute les bits depuis mon stream, s’il y
en a, pour reconstruire mon état tel qu’il devrait être.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="n">state</span> <span class="o">&lt;</span> <span class="mi">2usize</span><span class="nf">.pow</span><span class="p">(</span><span class="mi">16</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// Si on a un état &lt; 16, on essaye de lire le stream.</span>
    <span class="c1">// Dans le cas où on avait shifté, le stream contient</span>
    <span class="c1">// forcément des bits. Si on ne trouve pas de bits,</span>
    <span class="c1">// ça veut dire qu'on arrive à la fin de la decompression,</span>
    <span class="c1">// là où l'état a naturellement une petite taille.</span>
    <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">nb_bits</span><span class="p">)</span> <span class="o">=</span> <span class="n">bits</span><span class="nf">.pop</span><span class="p">()</span> <span class="p">{</span>
        <span class="n">state</span> <span class="o">=</span> <span class="p">(</span><span class="n">state</span> <span class="o">&lt;&lt;</span> <span class="mi">16</span><span class="p">)</span> <span class="o">+</span> <span class="n">dstream</span><span class="nf">.read</span><span class="p">(</span><span class="n">nb_bits</span> <span class="k">as</span> <span class="nb">u8</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">()</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="conclusion-">Conclusion ?</h2>

<p>C’est un peu prématuré comme fin. Non ? Moi j’ai envie d’en savoir plus en tout cas.</p>

<p>Comme d’habitude, en fouillant un peu dans mon code<em>bucket sur github vous
trouverez un peu de code. Lorsque le code sera mature j’en ferai une
bibliothèque bien sûr. N’hésitez pas à me poser une question sur ce répo ou en
MP par mail. Je serai content de vous aider, ou du moins _essayer</em>.</p>

<p>Pour l’instant, je ne peux que conclure que la compression de données, c’est
compliqué. Par exemple, cet article fait une taille environ de 238000 bits. Avec
un huffman et un alphabet de symboles de 8 bits, j’arrive à compresser vers
145000 bits. Tandis qu’avec FSE, sur le même alphabet, je suis à 173000.</p>

<p>Il y a tellement de variables à prendre en compte. Trouver la bonne répartition
des symboles n’est pas évident, déjà, puis avec FSE on peut varier la précision
et la taille de l’état. Ça peut tout changer ! Lorsque je compresse cet article
avec un FSE et un alphabet de symboles de 16 bits, j’arrive quand même à
compresser vers 138000 bits.</p>

<p>Enfin bref, je vous tiens au courant ! Prochaines étapes, regarder la
normalisation, LZW, Huffman vs FSE et compressions arithmétiques scalables !</p>

<p>À bientôt !</p>]]></content><author><name>Adrien Zinger</name></author><summary type="html"><![CDATA[Ces derniers mois j'ai passé la plupart de mon temps libre à étudier plusieurs algorithmes de compression. J'y ai passé tellement de temps que mon entourage à commencé à surnommer ça "la quête". Je vous partage un peu de mon enthousiasme en Français, ma langue natale. Des réponses, mais surtout des questions, sur l'ANS (FSE), sur des méthodes arithmétiques et d'autres plus classiques.]]></summary></entry><entry><title type="html">Sister’s wedding</title><link href="https://www.maybeuninit.com/2022/07/18/sisters-wedding.html" rel="alternate" type="text/html" title="Sister’s wedding" /><published>2022-07-18T00:00:00+00:00</published><updated>2022-07-18T00:00:00+00:00</updated><id>https://www.maybeuninit.com/2022/07/18/sisters-wedding</id><content type="html" xml:base="https://www.maybeuninit.com/2022/07/18/sisters-wedding.html"><![CDATA[<h1 id="sisters-wedding">Sister’s wedding</h1>
<p><span style="color: #A0A0A0">[2022-07-18] #Rust #GeneticAlgorithm #WASM</span></p>

<blockquote>
  <p>Article is being checked ;) the demo works only on firefox for now.</p>
</blockquote>

<hr />

<h2 id="live-snippet">Live snippet</h2>

<p>Full result at the end of the article ;)</p>

<div class="container-fluid">
    <div class="row">
        <div class="col">
            <div class="input-group mb-3">
                <input id="input-names" type="text" class="form-control" placeholder="Name" aria-label="Name" aria-describedby="input-name" />
            </div>
            <ul class="list-group">
                <li id="name1" class="list-group-item active"></li>
                <li id="name2" class="list-group-item"></li>
                <li id="name3" class="list-group-item"></li>
                <li id="name4" class="list-group-item"></li>
            </ul>
        </div>
        <div class="col">
            <div class="input-group mb-3">
                <input id="input-bonus" type="text" class="form-control" placeholder="Bonus" aria-label="Bonus" aria-describedby="input-bonus" />
            </div>
            <ul id="bonus" class="list-group">
                <li id="bonus1" class="list-group-item active"></li>
                <li id="bonus2" class="list-group-item"></li>
                <li id="bonus3" class="list-group-item"></li>
                <li id="bonus4" class="list-group-item"></li>
            </ul>
        </div>
    </div>
    <div class="row">
        <div class="col">
            <div class="input-group mb-3">
                <input id="input-penalties" type="text" class="form-control" placeholder="Penalties" aria-label="Penalties" aria-describedby="input-penalties" />
            </div>
            <ul id="penalties" class="list-group">
                <li id="penalties1" class="list-group-item active"></li>
                <li id="penalties2" class="list-group-item"></li>
                <li id="penalties3" class="list-group-item"></li>
                <li id="penalties4" class="list-group-item"></li>
            </ul>
        </div>
        <div class="col">
            <div class="input-group mb-3">
                <input id="input-result" type="text" class="form-control" placeholder="Result" disabled="" style="background-color: transparent !important; color: white !important" />
            </div>
            <ul id="result" class="list-group">
                <li id="result1" class="list-group-item active" style="color: grey !important;">.</li>
                <li id="result2" class="list-group-item" style="color: grey !important;">.</li>
                <li id="result3" class="list-group-item" style="color: grey !important;">.</li>
                <li id="result4" class="list-group-item" style="color: grey !important;">.</li>
            </ul>
        </div>
    </div>
    <div class="row">
        <button type="button" class="btn btn-primary" onclick="reset()">Reset</button>
    </div>
</div>

<hr />
<p><br /></p>

<h2 id="my-sister-is-getting-married">My sister is getting married!</h2>

<p>We’re talking about serious things!!</p>

<p>Speaking with my sister, we talked about some people at the wedding who
can’t be together at the table. Then, we felt about the issue, how to
propperly position people? For example, I want to be with my girlfriend and
my daughter, but Barney wants to be with his crush, who doesn’t want
to speak with her ex-best friend! Multiply that kind of story by 100,
and you finish with a wedding burnout.</p>

<p><img style="max-width: 500px;" src="https://www.maybeuninit.com/assets/img/bureaucracy.gif" alt="crack" /></p>

<p>One of the firsts <em>little easy algorithm</em> I learned is the genetic one.
And May be it can help my sister to do his table plan… I’ll do a special article
with a code snippet.</p>

<h2 id="code">Code</h2>

<p>A genetic algorithm is just a smart method to bruteforce a problem such as the
famous “Traveling salesman”. You’ll never be sure that the result is the
best. Nevertheless, you’ll have a better result than an approximation, and
in a reasonable time.</p>

<p>I’m not going to explain step by step the principle of the genetic method. If
you’re interested, you can look at these videos of <a href="https://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=&amp;cad=rja&amp;uact=8&amp;ved=2ahUKEwjnoJme_oH5AhUzh_0HHTNmAwkQwqsBegQIEhAB&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D9zfeTw-uFCw&amp;usg=AOvVaw2r19VpTmdolkAXJpaZDJv7">The coding train channel</a>.</p>

<p>I propose to show, how with perhaps 200 lines of rust I can write a web library
with a genetic algorithm, specific for a table’s plan.</p>

<h3 id="types">Types</h3>

<p>When I start a genetic algorithm, I like to start with the definition of
DNA. An option for our case is to use a vector of tables and store
the names of the participants.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">type</span> <span class="n">Dna</span> <span class="o">=</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;&gt;</span><span class="p">;</span>
</code></pre></div></div>

<p>A way to judge a DNA, is to create penalties and
bonuses. Penalties are applied when two participants who
are not “compatible” are in the same table. I give bonuses
similarly, when good friends are together.</p>

<p>Penalty key: two names separated with a coma in alphabetical order.
Penalty value: value of the penalty. (0 to 255)</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">type</span> <span class="n">Penalties</span> <span class="o">=</span> <span class="n">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span> <span class="nb">u8</span><span class="o">&gt;</span><span class="p">;</span>
<span class="k">pub</span> <span class="k">type</span> <span class="n">Bonus</span> <span class="o">=</span> <span class="n">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span> <span class="nb">u8</span><span class="o">&gt;</span><span class="p">;</span>
</code></pre></div></div>

<p>Number of people in the population. I Don’t need much, 100 is more
than enough. If we want a better result, we prefer to increase the number of
generations.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static</span> <span class="n">N</span><span class="p">:</span> <span class="nb">usize</span> <span class="o">=</span> <span class="mi">100</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="evaluation">Evaluation</h3>

<p>There is no genetic algorithm without evaluations! The function will
compute a value from a DNA, then we will order the bests rated candidates
and merge them together.</p>

<p>The evaluation can be very naive! If two people with a bonus are at
the same table, we add the bonus’s value. If two people with a penalty
are at the same table, we subtract the penalty’s value (all of that
in the range of an unsigned 32 bits integer)</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">evaluation</span><span class="p">(</span><span class="n">dna</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Dna</span><span class="p">,</span> <span class="n">penalties</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Penalties</span><span class="p">,</span> <span class="n">bonus</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Bonus</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">u32</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">ret</span> <span class="o">=</span> <span class="mi">0i64</span><span class="p">;</span>
    <span class="k">for</span> <span class="n">table</span> <span class="k">in</span> <span class="n">dna</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">couples</span> <span class="o">=</span>
            <span class="nn">HashSet</span><span class="p">::</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="p">::</span><span class="nf">from_iter</span><span class="p">(</span><span class="n">table</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.combinations</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span><span class="nf">.map</span><span class="p">(|</span><span class="n">c</span><span class="p">|</span> <span class="nf">couple</span><span class="p">(</span><span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">c</span><span class="p">[</span><span class="mi">1</span><span class="p">])));</span>
        <span class="k">for</span> <span class="n">couple</span> <span class="k">in</span> <span class="n">couples</span><span class="nf">.iter</span><span class="p">()</span> <span class="p">{</span>
            <span class="n">ret</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span>
            <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="o">=</span> <span class="n">bonus</span><span class="nf">.get</span><span class="p">(</span><span class="n">couple</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">ret</span> <span class="o">=</span> <span class="n">ret</span><span class="nf">.saturating_add</span><span class="p">(</span><span class="o">*</span><span class="n">v</span> <span class="k">as</span> <span class="nb">i64</span><span class="p">);</span>
            <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="k">let</span> <span class="nf">Some</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="o">=</span> <span class="n">penalties</span><span class="nf">.get</span><span class="p">(</span><span class="n">couple</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">ret</span> <span class="o">=</span> <span class="n">ret</span><span class="nf">.saturating_sub</span><span class="p">(</span><span class="o">*</span><span class="n">v</span> <span class="k">as</span> <span class="nb">i64</span><span class="p">)</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="k">match</span> <span class="n">ret</span><span class="nf">.try_into</span><span class="p">()</span> <span class="p">{</span>
        <span class="nf">Ok</span><span class="p">(</span><span class="n">ret</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">ret</span><span class="p">,</span>
        <span class="n">_</span> <span class="k">=&gt;</span> <span class="mi">0</span><span class="p">,</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="merging-reproduction">Merging (reproduction)</h3>

<p>Once you have a population (the list of DNAs), and you have evaluated each
person. You can order them and “merge” the half of the bests between them.</p>

<p>To merge two DNAs, you call that function. It will shuffle some places and
create a new random one.</p>

<p>What do I try to do? First, if <code class="language-plaintext highlighter-rouge">a</code> and <code class="language-plaintext highlighter-rouge">b</code> are equals, I just return <code class="language-plaintext highlighter-rouge">a</code> and
avoid useless execution of codes. Then I take the table length, in theory,
there shouldn’t be a problem here to take the first element of <code class="language-plaintext highlighter-rouge">a</code>.</p>

<p>Then I flatten the names. I have to list of names ordered by there position in
the wedding. At the position <code class="language-plaintext highlighter-rouge">0</code>, we have the name of the person at table 1
place 1. At position <code class="language-plaintext highlighter-rouge">1</code>, we have the name for table 1, position 2, etc.</p>

<p>I can shuffle manually the places, taking randomly the piece of DNA from the
parent <code class="language-plaintext highlighter-rouge">a</code>, or from the parent <code class="language-plaintext highlighter-rouge">b</code>. As it would work in the real life I
guess.</p>

<p>Note that I also add a possibility to create a random DNA from nowhere.
That’s a natural mutation that will add a natural branch of evolution
if it’s very good, or just die at the next generation. Sad, but life can be
terrible.</p>

<p>To keep coherency, if you choose the one from the parent <code class="language-plaintext highlighter-rouge">a</code>,
I need to say that <code class="language-plaintext highlighter-rouge">b</code> should replace the chosen name by the other.</p>

<p>In other words, for each element in the DNA, I choose to use the second
element or restore the first element.</p>

<p>Note: there is probably a lot of cloning that I can avoid! If you want to
share an idea you can post a comment ;)</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">merge</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Dna</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="o">&amp;</span><span class="n">Dna</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">Dna</span> <span class="p">{</span>
    <span class="k">if</span> <span class="n">a</span> <span class="o">==</span> <span class="n">b</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">a</span><span class="nf">.clone</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="k">let</span> <span class="n">table_length</span> <span class="o">=</span> <span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="nf">.len</span><span class="p">();</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">a</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span> <span class="o">=</span> <span class="n">a</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.flatten</span><span class="p">()</span><span class="nf">.cloned</span><span class="p">()</span><span class="nf">.collect</span><span class="p">();</span>
    <span class="k">if</span> <span class="nn">rand</span><span class="p">::</span><span class="nn">random</span><span class="p">::</span><span class="o">&lt;</span><span class="nb">u8</span><span class="o">&gt;</span><span class="p">()</span> <span class="o">&gt;</span> <span class="mi">254</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nf">random</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">table_length</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="k">let</span> <span class="n">b</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span> <span class="o">=</span> <span class="n">b</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.flatten</span><span class="p">()</span><span class="nf">.cloned</span><span class="p">()</span><span class="nf">.collect</span><span class="p">();</span>

    <span class="k">let</span> <span class="k">mut</span> <span class="n">rng</span> <span class="o">=</span> <span class="nn">rand</span><span class="p">::</span><span class="nf">thread_rng</span><span class="p">();</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">pos</span> <span class="o">=</span>
        <span class="nn">HashMap</span><span class="p">::</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span> <span class="nb">usize</span><span class="o">&gt;</span><span class="p">::</span><span class="nf">from_iter</span><span class="p">(</span><span class="n">a</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.enumerate</span><span class="p">()</span><span class="nf">.map</span><span class="p">(|(</span><span class="n">i</span><span class="p">,</span> <span class="n">v</span><span class="p">)|</span> <span class="p">(</span><span class="n">v</span><span class="nf">.clone</span><span class="p">(),</span> <span class="n">i</span><span class="p">)));</span>
    <span class="k">let</span> <span class="n">mem</span> <span class="o">=</span> <span class="n">a</span><span class="nf">.clone</span><span class="p">();</span>

    <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">a</span><span class="nf">.len</span><span class="p">()</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">n</span> <span class="o">=</span> <span class="k">match</span> <span class="n">rng</span><span class="nf">.gen</span><span class="p">()</span> <span class="p">{</span>
            <span class="k">true</span> <span class="k">=&gt;</span> <span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="nf">.clone</span><span class="p">(),</span> <span class="c1">// replace</span>
            <span class="n">_</span> <span class="k">=&gt;</span> <span class="n">mem</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="nf">.clone</span><span class="p">(),</span>  <span class="c1">// restore</span>
        <span class="p">};</span>
        <span class="k">let</span> <span class="n">pn</span> <span class="o">=</span> <span class="o">*</span><span class="n">pos</span><span class="nf">.get</span><span class="p">(</span><span class="o">&amp;</span><span class="n">n</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">();</span>
        <span class="k">let</span> <span class="n">o</span> <span class="o">=</span> <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="nf">.clone</span><span class="p">();</span>
        <span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">n</span><span class="nf">.clone</span><span class="p">();</span>
        <span class="n">a</span><span class="p">[</span><span class="n">pn</span><span class="p">]</span> <span class="o">=</span> <span class="n">o</span><span class="nf">.clone</span><span class="p">();</span>
        <span class="n">pos</span><span class="nf">.insert</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span>
        <span class="n">pos</span><span class="nf">.insert</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="n">pn</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">a</span><span class="nf">.chunks</span><span class="p">(</span><span class="n">table_length</span><span class="p">)</span><span class="nf">.map</span><span class="p">(|</span><span class="n">t</span><span class="p">|</span> <span class="n">t</span><span class="nf">.to_vec</span><span class="p">())</span><span class="nf">.collect</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>

<blockquote>
  <p>That method is similar to merge two hashmaps and taking randomly the value.
It’s very long to get goods mutations that way. Sadly, a full shuffle of
the DNAs is a better solution right now. The main difference between
“bruteforce” and “genetic” is the effort we make to choose and merge the best
results, a form of eugenics. Sometimes the data structures help us, not
today.</p>
</blockquote>

<h3 id="start-and-run-the-simulation">Start and run the simulation!</h3>

<p>Obviously, when we will get a list of participant, I want to create a
population for my experience. So I’ll call that <code class="language-plaintext highlighter-rouge">random</code> method that will
create a new DNA from a list of names and a table length.</p>

<p>Ill call that function N times, I don’t need so much, 100 would be great</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">random</span><span class="p">(</span><span class="k">mut</span> <span class="n">people</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">table_length</span><span class="p">:</span> <span class="nb">usize</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="n">Dna</span> <span class="p">{</span>
    <span class="n">people</span><span class="nf">.shuffle</span><span class="p">(</span><span class="o">&amp;</span><span class="k">mut</span> <span class="nn">rand</span><span class="p">::</span><span class="nf">thread_rng</span><span class="p">());</span>
    <span class="n">people</span><span class="nf">.chunks</span><span class="p">(</span><span class="n">table_length</span><span class="p">)</span><span class="nf">.map</span><span class="p">(|</span><span class="n">t</span><span class="p">|</span> <span class="n">t</span><span class="nf">.to_vec</span><span class="p">())</span><span class="nf">.collect</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Now, we got everything, I can start the genetic algorithm. I take in input a
population, some penalties, some bonus, the number of participants in a
table. And a log function for reporting progress in a callback.</p>

<p>The <code class="language-plaintext highlighter-rouge">times</code> input significate the number of generations of the genetic
evolution.</p>

<p>I also want to return the latest bests DNA in my population. As well, I can
call <code class="language-plaintext highlighter-rouge">run</code> or <code class="language-plaintext highlighter-rouge">rerun</code>, where run will create a random population, and rerun
will use a population in input (and that is convenient that the input is
the previous bests returned by <code class="language-plaintext highlighter-rouge">run</code>).</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">intern_run</span><span class="p">(</span>
    <span class="n">times</span><span class="p">:</span> <span class="nb">usize</span><span class="p">,</span>
    <span class="k">mut</span> <span class="n">population</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Dna</span><span class="o">&gt;</span><span class="p">,</span>
    <span class="n">penalties</span><span class="p">:</span> <span class="n">Penalties</span><span class="p">,</span>
    <span class="n">bonus</span><span class="p">:</span> <span class="n">Bonus</span><span class="p">,</span>
    <span class="k">log</span><span class="p">:</span> <span class="k">fn</span><span class="p">(</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">Vec</span><span class="o">&lt;</span><span class="nb">String</span><span class="o">&gt;&gt;</span><span class="p">,</span> <span class="nb">usize</span><span class="p">),</span>
<span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Dna</span><span class="o">&gt;</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">rng</span> <span class="o">=</span> <span class="nn">rand</span><span class="p">::</span><span class="nf">thread_rng</span><span class="p">();</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">ret</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;</span><span class="n">Dna</span><span class="o">&gt;</span> <span class="o">=</span> <span class="nd">vec!</span><span class="p">[];</span>
    <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="n">times</span> <span class="p">{</span>
        <span class="k">let</span> <span class="n">bests</span><span class="p">:</span> <span class="nb">Vec</span><span class="o">&lt;&amp;</span><span class="n">Dna</span><span class="o">&gt;</span> <span class="o">=</span> <span class="n">population</span>
            <span class="nf">.iter</span><span class="p">()</span>
            <span class="nf">.sorted_by_cached_key</span><span class="p">(|</span><span class="n">dna</span><span class="p">|</span> <span class="nf">Reverse</span><span class="p">(</span><span class="nf">evaluation</span><span class="p">(</span><span class="n">dna</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">penalties</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">bonus</span><span class="p">)))</span>
            <span class="nf">.take</span><span class="p">(</span><span class="n">N</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)</span>
            <span class="nf">.collect</span><span class="p">();</span>
        <span class="k">log</span><span class="p">(</span>
            <span class="n">bests</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="nf">.clone</span><span class="p">(),</span>
            <span class="nf">evaluation</span><span class="p">(</span><span class="n">bests</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="o">&amp;</span><span class="n">penalties</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">bonus</span><span class="p">)</span> <span class="k">as</span> <span class="nb">usize</span><span class="p">,</span>
        <span class="p">);</span>
        <span class="k">if</span> <span class="n">i</span> <span class="o">==</span> <span class="n">times</span> <span class="o">-</span> <span class="mi">1</span> <span class="p">{</span>
            <span class="n">ret</span> <span class="o">=</span> <span class="n">bests</span><span class="nf">.iter</span><span class="p">()</span><span class="nf">.cloned</span><span class="p">()</span><span class="nf">.cloned</span><span class="p">()</span><span class="nf">.collect</span><span class="p">();</span>
        <span class="p">}</span>
        <span class="n">population</span> <span class="o">=</span> <span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="n">N</span><span class="p">)</span>
            <span class="nf">.map</span><span class="p">(|</span><span class="n">_</span><span class="p">|</span> <span class="p">{</span>
                <span class="nf">merge</span><span class="p">(</span>
                    <span class="n">bests</span><span class="p">[</span><span class="n">rng</span><span class="nf">.gen_range</span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="n">N</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)],</span>
                    <span class="n">bests</span><span class="p">[</span><span class="n">rng</span><span class="nf">.gen_range</span><span class="p">(</span><span class="mi">0</span><span class="o">..</span><span class="n">N</span> <span class="o">/</span> <span class="mi">2</span><span class="p">)],</span>
                <span class="p">)</span>
            <span class="p">})</span>
            <span class="nf">.collect</span><span class="p">();</span>
    <span class="p">}</span>
    <span class="n">ret</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Then some bindings with wasm-bindgen and I do the glue! Easy like that! You can
use the package, since there is no multithreading, and no thread locks, it compile
<em>like a charm</em>. The <em>JSON</em> serialization could be modified I think, creating more
glue manually, but not now!!</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">#[wasm_bindgen]</span>
<span class="k">pub</span> <span class="k">fn</span> <span class="nf">run</span><span class="p">(</span>
    <span class="n">times</span><span class="p">:</span> <span class="nb">usize</span><span class="p">,</span>
    <span class="n">people</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span>
    <span class="n">penalties</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span>
    <span class="n">bonus</span><span class="p">:</span> <span class="nb">String</span><span class="p">,</span>
    <span class="n">table_length</span><span class="p">:</span> <span class="nb">usize</span><span class="p">,</span>
<span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">String</span> <span class="p">{</span>
    <span class="k">let</span> <span class="n">_</span><span class="p">:</span> <span class="n">HashMap</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span> <span class="nb">u8</span><span class="o">&gt;</span> <span class="o">=</span> <span class="k">match</span> <span class="nn">serde_json</span><span class="p">::</span><span class="nf">from_str</span><span class="p">(</span><span class="o">&amp;</span><span class="n">penalties</span><span class="p">)</span> <span class="p">{</span>
        <span class="nf">Ok</span><span class="p">(</span><span class="n">p</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="n">p</span><span class="p">,</span>
        <span class="nf">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span> <span class="k">=&gt;</span> <span class="p">{</span>
            <span class="nf">elog</span><span class="p">(</span><span class="o">&amp;</span><span class="n">e</span><span class="nf">.to_string</span><span class="p">());</span>
            <span class="nd">panic!</span><span class="p">()</span>
        <span class="p">}</span>
    <span class="p">};</span>
    <span class="nn">serde_json</span><span class="p">::</span><span class="nf">to_string</span><span class="p">(</span><span class="o">&amp;</span><span class="nn">algo</span><span class="p">::</span><span class="nf">run</span><span class="p">(</span>
        <span class="n">times</span><span class="p">,</span>
        <span class="nn">serde_json</span><span class="p">::</span><span class="nf">from_str</span><span class="p">(</span><span class="o">&amp;</span><span class="n">people</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">(),</span>
        <span class="nn">serde_json</span><span class="p">::</span><span class="nf">from_str</span><span class="p">(</span><span class="o">&amp;</span><span class="n">penalties</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">(),</span>
        <span class="nn">serde_json</span><span class="p">::</span><span class="nf">from_str</span><span class="p">(</span><span class="o">&amp;</span><span class="n">bonus</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">(),</span>
        <span class="n">table_length</span><span class="p">,</span>
        <span class="p">|</span><span class="n">dna</span><span class="p">,</span> <span class="n">e</span><span class="p">|</span> <span class="p">{</span>
            <span class="nd">#[allow(unused_unsafe)]</span>
            <span class="k">unsafe</span> <span class="p">{</span>
                <span class="nf">log_best</span><span class="p">(</span><span class="nn">serde_json</span><span class="p">::</span><span class="nf">to_string</span><span class="p">(</span><span class="o">&amp;</span><span class="n">dna</span><span class="p">)</span><span class="nf">.unwrap</span><span class="p">(),</span> <span class="n">e</span><span class="p">)</span>
            <span class="p">}</span>
        <span class="p">},</span>
    <span class="p">))</span>
    <span class="nf">.unwrap</span><span class="p">()</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Thank you for reading! I’ll share soon the full code of the project. Bellow
you can look at the full result of the computed table plan. The time you read
that, a lot of generations have lived and now, you have one of the best
possible proposal!</p>

<p>You can create you’re own list of participants by resetting the example, and
adding the names (press enter to add a name), and adding bonus / penalty
(name1 [space] name2, [number value]). Note that it probably work better if
you prefer to use more bonus than penalties.</p>

<p>Good day!</p>

<p><img style="max-width: 500px;" src="https://www.maybeuninit.com/assets/img/wedding.gif" alt="wedding" /></p>

<script type="module">

    import init, {run, rerun} from "/assets/js/wedding/sisters_wedding.js";
    let bests;

    function call_run() {
        if (names.length == 0) {
            return;
        }
        orderNames();
        bests = run(
            40,
            JSON.stringify(names),
            JSON.stringify(penalties),
            JSON.stringify(bonus),
            5
        );
        change = false; // set relaunch flag to false
    }

    let rerun_count = 0;
    function call_rerun() {
        orderNames();
        if (change || rerun_count > 10) {
            call_run();
            rerun_count = 0;
        } else {
            rerun_count++;
            bests = rerun(
                40,
                bests,
                JSON.stringify(penalties),
                JSON.stringify(bonus)
            );
        }
        setTimeout(call_rerun, 2000);
    }

    init().then(() => {
        call_run();
        setTimeout(call_rerun, 2000);
    });
</script>

<div class="container-fluid">
    <div class="row">
        <div class="col">
            <ul id="full-result" class="list-group">
            </ul>
        </div>
    </div>
</div>]]></content><author><name>Adrien Zinger</name></author><summary type="html"><![CDATA[I'm happy to inform you, that my sister is getting to be married!! Speaking with her, we started to talk about the problem of placing people. How to prepare a table plan?! Then I started to write a funny naive genetic algorithm...]]></summary></entry><entry><title type="html">Coding an hashmap from scratch… in webassembly</title><link href="https://www.maybeuninit.com/2022/06/10/wasm-hashtable.html" rel="alternate" type="text/html" title="Coding an hashmap from scratch… in webassembly" /><published>2022-06-10T00:00:00+00:00</published><updated>2022-06-10T00:00:00+00:00</updated><id>https://www.maybeuninit.com/2022/06/10/wasm-hashtable</id><content type="html" xml:base="https://www.maybeuninit.com/2022/06/10/wasm-hashtable.html"><![CDATA[<h1 id="coding-a-hashmap-from-scratch-in-webassembly">Coding a hashmap from scratch… in webassembly</h1>
<p><span style="color: #A0A0A0">[2022-05-18] #WASM #DataStructure</span></p>

<hr />

<p>At first, it’s strange and useless. I’m aware of that, the goal is not
to replace the data structures generated by <em>C</em>, <em>AssemblyScript</em>, <em>grain</em> or
whatever an higher level language that build to wasm. It’s something
you should do if you want to really understand what’s happening when you want
at some point do interoperability.</p>

<h2 id="first-some-words-about-webassembly">First, some words about webassembly</h2>

<p>Webassembly starts to get famous in the planet <em>informatic</em>. Nevertheless,
all use-cases where you consider to build a wasm require some kind of embedder.
In other words, you need to define an environment to execute your code using
another language. E.g. <em>nodejs</em>, <em>Rust</em> or at least a browser that support wasm!</p>

<blockquote>
  <p>Here is a list of
<a href="https://github.com/appcypher/awesome-wasm-runtimes" style="color: inherit !important;">
awesome wasm runtimes</a></p>
</blockquote>

<p>Once your done, you need to define how you manage the discussion between the
embedder (runtime) and the wasm instance.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nx">module</span>
  <span class="p">(</span><span class="nx">func</span> <span class="nx">$add</span> <span class="p">(</span><span class="nx">param</span> <span class="nx">$lhs</span> <span class="nx">i32</span><span class="p">)</span> <span class="p">(</span><span class="nx">param</span> <span class="nx">$rhs</span> <span class="nx">i32</span><span class="p">)</span> <span class="p">(</span><span class="nx">result</span> <span class="nx">i32</span><span class="p">)</span>
    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$lhs</span>
    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$rhs</span>
    <span class="nx">i32</span><span class="p">.</span><span class="nx">add</span><span class="p">)</span>
  <span class="p">(</span><span class="k">export</span> <span class="dl">"</span><span class="s2">add</span><span class="dl">"</span> <span class="p">(</span><span class="nx">func</span> <span class="nx">$add</span><span class="p">))</span>
<span class="p">)</span>
</code></pre></div></div>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">WebAssembly</span><span class="p">.</span><span class="nx">instantiateStreaming</span><span class="p">(</span><span class="nx">fetch</span><span class="p">(</span><span class="dl">'</span><span class="s1">add.wasm</span><span class="dl">'</span><span class="p">))</span>
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">obj</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">instance</span><span class="p">.</span><span class="nx">exports</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">));</span>  <span class="c1">// "3"</span>
<span class="p">});</span>
</code></pre></div></div>

<p>Here, we learn how to pass a simple <code class="language-plaintext highlighter-rouge">i32</code>. And then? What about a string? A
user-defined structure? The web seems to silent the fact that there is no
convention about it…</p>

<p>There is some good stuff that can help you if you work with
<em>Rust</em> that build to <em>wasm</em> and if you use the wasm in <em>Rust</em>.🐍
<a href="https://github.com/rustwasm/wasm-bindgen">wasm-bingen</a> is a good example of
a project that tend to unify everybody. But it’s not very flexible for now.</p>

<p>In conclusion, if you want some exotic stuff with wasm, you have to learn by
yourself how the data is represented in memory. And if you don’t want to drown, I
strongly recommend to you to learn and write in webassembly directly. (That’s very
fun!)</p>

<blockquote>
  <p>Have a look at another of my post about string concatenation
<a href="https://www.maybeuninit.com/2022/05/31/concat-wasm.html" style="color: inherit !important;">
here</a>. I speak about reading
and writing in an instance’s memory.</p>
</blockquote>

<h2 id="the-insert-method">The insert method</h2>

<p>The map I build in memory has a classic memory representation. First I
choose to create a map of 256 elements. And each of these element is a
32-bits address pointing to a list of elements, initialized to <code class="language-plaintext highlighter-rouge">0</code>.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>|-----    256    <span class="nt">-----</span>|
v                     v
+--+--+--+--+-.-+--+--+
| 0| 0| 0| 0| <span class="nb">.</span> | 0| 0|
+--+--+--+--+-.-+--+--+
</code></pre></div></div>

<p>The first thing I need to do is to check if there is something in the
map for my key, so basically I search the address of an item and
if the address is the impossible value <code class="language-plaintext highlighter-rouge">0</code>, it means that there is
no <code class="language-plaintext highlighter-rouge">key</code> in my map, so in the head of the list pointed by node I push
a new item.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="p">(</span><span class="nx">func</span> <span class="nx">$insert</span> <span class="p">(</span><span class="nx">param</span> <span class="nx">$map</span> <span class="nx">i32</span><span class="p">)</span> <span class="p">(</span><span class="nx">param</span> <span class="nx">$key</span> <span class="nx">i32</span><span class="p">)</span> <span class="p">(</span><span class="nx">param</span> <span class="nx">$val</span> <span class="nx">i32</span><span class="p">)</span>
        <span class="p">(</span><span class="nx">local</span> <span class="nx">$addr</span> <span class="nx">i32</span><span class="p">)</span>
        <span class="p">(</span><span class="nx">local</span> <span class="nx">$item</span> <span class="nx">i32</span><span class="p">)</span>
	<span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$map</span>
	<span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$key</span>
	<span class="nx">call</span> <span class="nx">$internal</span><span class="o">/</span><span class="nx">get_item_addr</span>
	<span class="nx">local</span><span class="p">.</span><span class="nx">tee</span> <span class="nx">$addr</span>
	<span class="nx">i32</span><span class="p">.</span><span class="nx">eqz</span>
	<span class="p">(</span><span class="k">if</span>
  	  <span class="p">(</span><span class="nx">then</span>
	    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$map</span>
	    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$key</span>
	    <span class="nx">call</span> <span class="nx">$internal</span><span class="o">/</span><span class="nx">get_key_addr</span>    <span class="c1">// Addr in the map</span>
	    <span class="nx">local</span><span class="p">.</span><span class="nx">tee</span> <span class="nx">$addr</span>

	    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$key</span>
	    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$val</span>
	    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$addr</span>                <span class="c1">// Addr contains the current head pointer</span>
	    <span class="nx">i32</span><span class="p">.</span><span class="nx">load</span>                       <span class="c1">// Load the pointer</span>
	    <span class="nx">call</span> <span class="nx">$internal</span><span class="o">/</span><span class="nx">new_item</span>        <span class="c1">// Creates an item pointing to the previous</span>
	                                   <span class="c1">//             head and returns his address</span>
	    <span class="nx">i32</span><span class="p">.</span><span class="nx">store</span>                      <span class="c1">// Replace the old address by the new in the map</span>
	  <span class="p">)</span>
	  <span class="p">(</span><span class="k">else</span>                            <span class="c1">// Simply replace the old value at the offset 32</span>
	                                   <span class="c1">// with the new value.</span>
	    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$addr</span>
	    <span class="nx">i32</span><span class="p">.</span><span class="kd">const</span> <span class="mi">32</span>
	    <span class="nx">i32</span><span class="p">.</span><span class="nx">add</span>
	    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$val</span>
	    <span class="nx">i32</span><span class="p">.</span><span class="nx">store</span>
	  <span class="p">)</span>
	<span class="p">)</span>
 <span class="p">)</span>
<span class="p">)</span>
</code></pre></div></div>

<h2 id="get-an-item">Get an item</h2>

<p>The function <code class="language-plaintext highlighter-rouge">$internal/get_key_addr</code> used in the previous don’t just
looks at the address pointed by the key hash on my map. But it looks through
an array-list if my key is stored. It’s maybe something you didn’t get
before but a map is’nt simply <code class="language-plaintext highlighter-rouge">Θ(1)</code> in any cases. It could be if the map
had an infinite size. Unfortunately, it’s impossible.</p>

<p>I let you look at my favorite scientific website for more information
about <em>hash table</em>, wikipedia.</p>

<ol>
  <li>Get the address of the head (in my map)</li>
  <li>Search in the array-list the key</li>
  <li>Return the address where the value is stored, or <code class="language-plaintext highlighter-rouge">0</code></li>
</ol>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nx">func</span> <span class="nx">$internal</span><span class="o">/</span><span class="nx">find</span> <span class="p">(</span><span class="nx">param</span> <span class="nx">$addr</span> <span class="nx">i32</span><span class="p">)</span> <span class="p">(</span><span class="nx">param</span> <span class="nx">$key</span> <span class="nx">i32</span><span class="p">)</span> <span class="p">(</span><span class="nx">result</span> <span class="nx">i32</span><span class="p">)</span>
	<span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$addr</span>
	<span class="nx">i32</span><span class="p">.</span><span class="nx">eqz</span>
	<span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nx">then</span>                <span class="c1">// early return if address is 0</span>
	   <span class="nx">i32</span><span class="p">.</span><span class="kd">const</span> <span class="mi">0</span>
	   <span class="k">return</span>
	<span class="p">))</span>
	<span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$addr</span>
	<span class="nx">i32</span><span class="p">.</span><span class="nx">load</span>                 <span class="c1">// load key, require kv addr on</span>
	                         <span class="c1">//  the stack</span>
	<span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$key</span>
	<span class="nx">i32</span><span class="p">.</span><span class="nx">eq</span>
	<span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nx">result</span> <span class="nx">i32</span><span class="p">)</span>
	  <span class="p">(</span><span class="nx">then</span> <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$addr</span><span class="p">)</span> <span class="c1">// found! break the recursion and return</span>
	                         <span class="c1">//  the address</span>

	  <span class="p">(</span><span class="k">else</span>                  <span class="c1">// go to next addr and repeat</span>
	    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$addr</span>
	    <span class="nx">i32</span><span class="p">.</span><span class="kd">const</span> <span class="mi">64</span>
	    <span class="nx">i32</span><span class="p">.</span><span class="nx">add</span>
	    <span class="nx">i32</span><span class="p">.</span><span class="nx">load</span>
	    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$key</span>
	    <span class="nx">call</span> <span class="nx">$internal</span><span class="o">/</span><span class="nx">find</span>
	  <span class="p">)</span>
	<span class="p">)</span>
 <span class="p">)</span>
</code></pre></div></div>

<h2 id="where-i-cheat">Where I cheat</h2>

<p>I cheat a little bit, because I only accept <code class="language-plaintext highlighter-rouge">i32</code> as keys and values. My
hashing function is a simple hash by division. And I don’t think about the
free of all of this. I’ll implement that stuff later! 😂</p>

<p>Anyway, that was very fun, I you want to look at the full code and how I
use it in a <em>JS</em> environment, have a look at the sources
<a href="https://github.com/adrien-zinger/code_bucket/tree/main/hashmap_wasm">here</a>.</p>]]></content><author><name>Adrien Zinger</name></author><summary type="html"><![CDATA[Why I wanted to develop an hashmap in webassembly.]]></summary></entry><entry><title type="html">String concatenation in webassembly</title><link href="https://www.maybeuninit.com/2022/05/31/concat-wasm.html" rel="alternate" type="text/html" title="String concatenation in webassembly" /><published>2022-05-31T00:00:00+00:00</published><updated>2022-05-31T00:00:00+00:00</updated><id>https://www.maybeuninit.com/2022/05/31/concat-wasm</id><content type="html" xml:base="https://www.maybeuninit.com/2022/05/31/concat-wasm.html"><![CDATA[<h2 id="string-concatenation-in-webassembly">String concatenation in webassembly</h2>

<p><span style="color: #A0A0A0">[2022-05-31] #JS #wasm #interoperability</span></p>

<hr />

<p>Dealing with memory in webassembly can be difficult to understand. But, actually,
it is not so hard.</p>

<p>The thing to understand is that wasm modules leave in separated instances
inside a <em>VM</em>. The <em>VM</em> is the executor, manage behind the scene the
validation of the module, the execution. It manages the stack machines,
the global variables and the <em>heap</em>.</p>

<p>Instances are fully described in the wasm code. In webassembly text, you
can know how is initialized the instance’s memory when you see that
kind of lines:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="p">(</span><span class="nx">memory</span> <span class="p">(</span><span class="k">export</span> <span class="dl">"</span><span class="s2">memory</span><span class="dl">"</span><span class="p">)</span> <span class="mi">1</span><span class="p">)</span>
  <span class="p">(</span><span class="nx">data</span> <span class="p">(</span><span class="nx">i32</span><span class="p">.</span><span class="kd">const</span> <span class="mi">0</span><span class="p">)</span> <span class="dl">"</span><span class="s2">hi</span><span class="dl">"</span><span class="p">)</span>
</code></pre></div></div>

<p>Here, I declare a memory of one page and a data “<code class="language-plaintext highlighter-rouge">hi</code>” in ascii at
position 0.</p>

<p>The binary describes the memory management.
So there is nothing like <em>garbage collection</em>. Furthermore, because in
a navigator, the environment manage mainly the memory of your
JS code. So you cannot safely let the memories being shared
like as in a classical dynamically linked library between compiled codes.</p>

<blockquote>
  <p>It’s actually possible to share the memory between multiple modules. Exactly
like the linking of a <em>Rust</em> and a <em>C</em> library. With the difference in a classical dynamic
link you don’t have to specify it explicitelly.</p>

  <p>Emscripten can produce wasm that are dynamically linked together. You can
so compile a C code into a webassembly binary and deal with shared memories between
two wasm.</p>

  <p>In the future, it would be neat to be able to share the
memory with C/C++/Rust code compiled into classical binaries
and an instance of webassembly created by an embedder like
<em>wasmtime</em> or <em>wasmer</em>.</p>

  <p>Note: WebAssembly is not a VM, even if we define some features and configurations
related to the VM inside it. It means that we don’t have nativelly a garbage collector.
However, according to the binary structure, the embedder can define one
like the JS/Python VM does.
For example, you can for each value walk through their dependencies,
and delete any unreachables objects. Or simply, you
can store for each value a <code class="language-plaintext highlighter-rouge">pin</code> flag, then, on trigger the garbage collector, remove
any structures without this flag. 👏</p>
</blockquote>

<h2 id="writing-a-string">Writing a string</h2>

<p>The calls of a wasm function from the embedder can only transfer primitive
value as <code class="language-plaintext highlighter-rouge">i32</code> or <code class="language-plaintext highlighter-rouge">i64</code>, if we want to share a string, we need to write inside
the instance memories.</p>

<p>To do that, we first need to share with the embedder the
memory. We need to import or export it.</p>

<p>Ex: export a memory of one page.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="p">(</span><span class="nx">memory</span> <span class="p">(</span><span class="k">export</span> <span class="dl">"</span><span class="s2">memory</span><span class="dl">"</span><span class="p">)</span> <span class="mi">1</span><span class="p">)</span>
</code></pre></div></div>

<p>In the JS side, I write from the position <em>8 x 20</em> the charcodes
of <code class="language-plaintext highlighter-rouge">hello\0</code> string in the exported memory :)</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="kd">const</span> <span class="p">{</span> <span class="nx">concat</span><span class="p">,</span> <span class="nx">memory</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">wasmModule</span><span class="p">.</span><span class="nx">instance</span><span class="p">.</span><span class="nx">exports</span><span class="p">;</span>
    <span class="c1">// define a C-style string</span>
    <span class="kd">let</span> <span class="nx">hello</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">hello</span><span class="se">\</span><span class="s2">0</span><span class="dl">"</span><span class="p">;</span>
    <span class="c1">// get the memory of the module</span>
    <span class="kd">let</span> <span class="nx">buf</span> <span class="o">=</span> <span class="nx">memory</span><span class="p">.</span><span class="nx">buffer</span><span class="p">;</span>
    <span class="kd">let</span> <span class="nx">mem_arr</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint8Array</span><span class="p">(</span><span class="nx">buf</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">hello</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="o">++</span><span class="nx">i</span><span class="p">)</span> <span class="p">{</span>
	<span class="nx">mem_arr</span><span class="p">[</span><span class="mi">20</span> <span class="o">+</span> <span class="nx">i</span><span class="p">]</span> <span class="o">=</span> <span class="nx">hello</span><span class="p">.</span><span class="nx">charCodeAt</span><span class="p">(</span><span class="nx">i</span><span class="p">);</span>
    <span class="p">}</span>
</code></pre></div></div>

<p>Be careful! There is nothing that prevent you to write over a value already in
the shared memory. You could try to <em>grow</em> the memory of one page, so you’re sure
the memory chunk where you’re about to write is free to use. You can also let
the module tell you where you can write if there is an allocator inside.</p>

<p>Like that too simple but enough allocator, for example:</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="p">(</span><span class="nx">func</span> <span class="nx">$wrong_malloc</span> <span class="p">(</span><span class="nx">param</span> <span class="nx">$0</span> <span class="nx">i32</span><span class="p">)</span> <span class="p">(</span><span class="nx">result</span> <span class="nx">i32</span><span class="p">)</span>
        <span class="p">(</span><span class="nx">local</span> <span class="nx">$ret</span> <span class="nx">i32</span><span class="p">)</span>
        <span class="nb">global</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$heap_head</span>
	<span class="nx">local</span><span class="p">.</span><span class="nx">tee</span> <span class="nx">$ret</span>
	<span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$0</span>
	<span class="nx">i32</span><span class="p">.</span><span class="nx">add</span>
	<span class="nb">global</span><span class="p">.</span><span class="kd">set</span> <span class="nx">$heap_head</span>
	<span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$ret</span>
 <span class="p">)</span>
</code></pre></div></div>

<h2 id="modify-the-string">Modify the string</h2>

<p>I write the string in the memory, then the charcodes are accessible in
the wasm.</p>

<p>Now I would like to expose a wasm function that append the word <em>world</em> to
anything I write in my variable. If I write the string at the position
<em>8 x 20</em>, I could call <code class="language-plaintext highlighter-rouge">concat(20)</code> (because it’s align to the 20th byte in memory).
That will read and find the end of the string,
and then continue to write ` world`.</p>

<p>Example: Store in the s param the next index after the last char
initialy, <code class="language-plaintext highlighter-rouge">s == 20</code> (given input arg).</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="p">(</span><span class="nx">loop</span> <span class="nx">$to_the_end</span>
    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$s</span>
    <span class="nx">i32</span><span class="p">.</span><span class="nx">load8_u</span>
    <span class="nx">i32</span><span class="p">.</span><span class="kd">const</span> <span class="mi">0</span>
    <span class="nx">i32</span><span class="p">.</span><span class="nx">gt_u</span>

    <span class="p">(</span><span class="k">if</span> <span class="p">(</span><span class="nx">result</span> <span class="nx">i32</span><span class="p">)</span>
      <span class="p">(</span><span class="nx">then</span>
        <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$s</span>
        <span class="nx">i32</span><span class="p">.</span><span class="kd">const</span> <span class="mi">1</span>
        <span class="nx">i32</span><span class="p">.</span><span class="nx">add</span>
        <span class="nx">local</span><span class="p">.</span><span class="nx">tee</span> <span class="nx">$s</span>
      <span class="p">)</span>
      <span class="p">(</span><span class="k">else</span>
        <span class="nx">i32</span><span class="p">.</span><span class="kd">const</span> <span class="mi">0</span>
      <span class="p">)</span>
    <span class="p">)</span>
    <span class="nx">i32</span><span class="p">.</span><span class="nx">gt_u</span>
    <span class="nx">br_if</span> <span class="nx">$to_the_end</span>
  <span class="p">)</span>
</code></pre></div></div>

<p>We already defined a string in the memory at the position <code class="language-plaintext highlighter-rouge">0</code>
containing the sequence <code class="language-plaintext highlighter-rouge">\ world</code> with this <code class="language-plaintext highlighter-rouge">(data (i32.const 0) " world")</code>.
So we can load it and copy each values of the string to
the last character.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="p">(</span><span class="nx">loop</span> <span class="nx">$dump</span>
    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$s</span>
    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$pos</span>
    <span class="nx">i32</span><span class="p">.</span><span class="nx">load8_u</span>
    <span class="nx">i32</span><span class="p">.</span><span class="nx">store8</span>

    <span class="nx">i32</span><span class="p">.</span><span class="kd">const</span> <span class="mi">1</span>
    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$s</span>
    <span class="nx">i32</span><span class="p">.</span><span class="nx">add</span>
    <span class="nx">local</span><span class="p">.</span><span class="kd">set</span> <span class="nx">$s</span>
    <span class="nx">i32</span><span class="p">.</span><span class="kd">const</span> <span class="mi">1</span>
    <span class="nx">local</span><span class="p">.</span><span class="kd">get</span> <span class="nx">$pos</span>
    <span class="nx">i32</span><span class="p">.</span><span class="nx">add</span>
    <span class="nx">local</span><span class="p">.</span><span class="nx">tee</span> <span class="nx">$pos</span>
    <span class="nx">i32</span><span class="p">.</span><span class="nx">load8_u</span>
    <span class="nx">i32</span><span class="p">.</span><span class="kd">const</span> <span class="mi">0</span>

    <span class="nx">i32</span><span class="p">.</span><span class="nx">gt_u</span>
    <span class="nx">br_if</span> <span class="nx">$dump</span>
  <span class="p">)</span>
<span class="p">)</span>
</code></pre></div></div>

<p>And then in the JS side you can just get back the address of the new string and read
enough of memory 😉</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="kd">let</span> <span class="nx">v</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Uint8Array</span><span class="p">(</span><span class="nx">memory</span><span class="p">.</span><span class="nx">buffer</span><span class="p">,</span> <span class="mi">20</span><span class="p">,</span> <span class="mi">50</span><span class="p">);</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="k">new</span> <span class="nx">TextDecoder</span><span class="p">(</span><span class="dl">'</span><span class="s1">utf8</span><span class="dl">'</span><span class="p">).</span><span class="nx">decode</span><span class="p">(</span><span class="nx">v</span><span class="p">));</span>
    <span class="c1">// hello world</span>
</code></pre></div></div>

<blockquote>
  <p>You can define better how the string is represented, you can use another
standard, send the address and the size of the string. As well you don’t
have to do the first loop. You can choose if your string will be in utf16
instead of the simple ascii.</p>

  <p>You can also invent your own encoding process! But I recommend to use some
known standard 😂</p>
</blockquote>

<p>The full code is on my bucket <a href="https://github.com/adrien-zinger/code_bucket/tree/main/wasm_strings">here</a>!</p>]]></content><author><name>Adrien Zinger</name></author><summary type="html"><![CDATA[Building a string concatenation in webassembly is the best entry point to understand the linear memory in a wasm instance. The whole point is how to represent a structure with a sequence of bytes. It is not so hard.]]></summary></entry><entry><title type="html">Templates, Concepts and traits</title><link href="https://www.maybeuninit.com/2022/05/18/meta-programming-ideas.html" rel="alternate" type="text/html" title="Templates, Concepts and traits" /><published>2022-05-18T00:00:00+00:00</published><updated>2022-05-18T00:00:00+00:00</updated><id>https://www.maybeuninit.com/2022/05/18/meta-programming-ideas</id><content type="html" xml:base="https://www.maybeuninit.com/2022/05/18/meta-programming-ideas.html"><![CDATA[<h2 id="templates-concepts-and-traits">Templates, Concepts and traits</h2>
<p><span style="color: #A0A0A0">[2022-05-18] #C++ #Rust #Traits</span></p>

<hr />

<p>The common point about these three words is that they all are
<em>programming ideas</em> and almost not related to any language feature.
Those are the kinds of ideas that are the soul of modern programming.</p>

<p>If <code class="language-plaintext highlighter-rouge">templates</code> and <code class="language-plaintext highlighter-rouge">concepts</code> are a similar in the sens that it allow
the user to do some <em>meta programming</em>, <code class="language-plaintext highlighter-rouge">traits</code> are an idiomatic system
to (and I quote <u> _Bjarn Stroustrup_ </u>) carry information used by
another object to determine <em>policy</em> or <em>implementation details</em>.</p>

<h2 id="about-templates">About templates</h2>

<p>In C++, templates are very common in the standard library. Even if it
tends to be replaced with concepts, you have probably already seen one
in your programmer’s life.</p>

<p>It’s all about genericness, if you’re building a library, you probably
want that the user could use it with any kind of input. If your library
is doing an abstract sequence of operations with the input, there is no
reasons to limit the client to a specific <em>Class</em>.</p>

<p>Note that in some cases you precisely <strong>want</strong> to be
specific. For example, when you build a lib with physic’s function, you
certainly want to introduce the specification of types like <code class="language-plaintext highlighter-rouge">Hz</code>, <code class="language-plaintext highlighter-rouge">km</code>.
You can so, remotely, introduce some rules of calculations and
assignations. That’s one example, but I’m sure there are many
other situations in which generic programming tools should not be used.</p>

<p>Unsurprisingly, templates take the form of <code class="language-plaintext highlighter-rouge">&lt; T &gt;</code> in many
languages. I’ll not go into details of the pattern because I’m sure you
can google it if you don’t know what is it.</p>

<h2 id="about-concepts">About concepts</h2>

<p>Hmf… 😬 In practice, concepts are very C++ oriented. But it introduces
the idea of <em>Constraints</em> that you cannot have with just templates!
Basically, it moves the resolution of the template very early in the
compilation and gives a flavor to the user to figure out why the type
doesn’t work with the library.</p>

<p>In other words:</p>

<ul>
  <li>with templates, you describe the constraints of the library in the
  documentation (the latest thing you read)</li>
  <li>with concepts, you let the compiler saying the constraints in a nice
  format 🙅</li>
</ul>

<h2 id="and-the-traits">And the traits</h2>

<p>Here is the bridge between Rust and C++ for the meta programming part.
In Rust, traits are used to describe both <em>Constraints</em> and
<em>implementation details</em>, where in C++, you need to do a mix of all the
ideas of that article.</p>

<p>Now, a basic example of an almost <em>word for word translation</em>. You can
decline it with any algorithm, nevertheless, I’m going to show how to do
the famous <code class="language-plaintext highlighter-rouge">ToString</code> traits constraints.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Declared in the standard library at std::string;</span>
<span class="c1">// Let user carry on the implementation for their own structures as `A`</span>
<span class="c1">// pub trait ToString {</span>
<span class="c1">// 	fn to_string(&amp;self) -&gt; String;</span>
<span class="c1">// }</span>

<span class="cd">/// Structure defined in the user program</span>
<span class="k">struct</span> <span class="n">A</span> <span class="p">{</span>
  <span class="c1">// parameters</span>
<span class="p">};</span>

<span class="cd">/// Implementation of the trait `ToString` for local structure `A`</span>
<span class="k">impl</span> <span class="n">ToString</span> <span class="k">for</span> <span class="n">A</span> <span class="p">{</span>
  <span class="k">fn</span> <span class="nf">to_string</span><span class="p">(</span><span class="o">&amp;</span><span class="k">self</span><span class="p">)</span> <span class="k">-&gt;</span> <span class="nb">String</span> <span class="p">{</span>
    <span class="c1">// implementation</span>
  <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>In rust, most of traits are already declared in the standard library
because it’s very idiomatic to work with. Note that as for a C++
parallel, the implementation for <code class="language-plaintext highlighter-rouge">A</code> isn’t <em>inside</em> <code class="language-plaintext highlighter-rouge">A</code>. It can, for
some reason, being implemented in another file that we would import if
we need <code class="language-plaintext highlighter-rouge">A</code> to implement the trait!</p>

<p>The library would constrain the used type to implement <code class="language-plaintext highlighter-rouge">ToString</code> like
that:</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">pub</span> <span class="k">fn</span> <span class="nf">foo</span><span class="p">(</span><span class="n">obj</span><span class="p">:</span> <span class="k">impl</span> <span class="n">ToString</span><span class="p">)</span> <span class="p">{</span>
  <span class="nd">println!</span><span class="p">(</span><span class="s">"{}"</span><span class="p">,</span> <span class="n">obj</span><span class="nf">.to_string</span><span class="p">());</span>
<span class="p">}</span>
</code></pre></div></div>

<p>So what is the C++ equivalent to the paradigm? First you need to declare
yourself the trait. Because C++ is not oriented like that and sometime
(I don’t understand why) people discourage to do it that way. If you
have got an idea please comment the post!</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// declare trait in lib.h</span>

<span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="nc">T</span><span class="p">&gt;</span>
<span class="k">struct</span> <span class="nc">trait_to_string</span> <span class="p">{</span>
  <span class="c1">// By default, we don't implement that trait for T</span>
  <span class="k">static</span> <span class="k">const</span> <span class="kt">bool</span> <span class="n">impl_flag</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
  <span class="k">static</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">to_string</span><span class="p">(</span><span class="k">const</span> <span class="n">T</span><span class="o">&amp;</span> <span class="n">self</span><span class="p">);</span>
<span class="p">};</span>
</code></pre></div></div>

<p>OK, so we are here with a <code class="language-plaintext highlighter-rouge">trait_to_string</code> that replace the standard in
Rust. And the structure <code class="language-plaintext highlighter-rouge">trait_to_string&lt;A&gt;</code> that implement the trait.</p>

<p>You’ve noticed that we already use templates here in <em>C++</em>, and not in
<em>Rust</em>. It’s because, behind the hood in <em>Rust</em> we are doing the same thing
(but in earlier in the compilation).</p>

<p>Now, we need to constrain the client to use our library with only data
that implement our trait <code class="language-plaintext highlighter-rouge">ToString-like</code>. We will use… <em>Concepts</em>!!</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// still in lib.h</span>

<span class="k">template</span><span class="o">&lt;</span><span class="k">typename</span> <span class="nc">T</span><span class="p">&gt;</span>
<span class="k">concept</span> <span class="n">ImplToString</span> <span class="o">=</span> <span class="k">requires</span><span class="p">(</span><span class="n">T</span> <span class="n">a</span><span class="p">)</span> <span class="p">{</span>
  <span class="c1">// required to be true</span>
  <span class="k">requires</span> <span class="n">trait_to_string</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">impl_flag</span><span class="p">;</span>
<span class="p">};</span>

<span class="cm">/**
* Export function log that is very simple...
*/</span>
<span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="nc">T</span><span class="p">&gt;</span>
<span class="k">requires</span> <span class="n">ImplToString</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">log</span><span class="p">(</span><span class="n">T</span> <span class="n">a</span><span class="p">)</span>
<span class="p">{</span>
  <span class="k">return</span> <span class="n">trait_to_string</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;::</span><span class="n">to_string</span><span class="p">(</span><span class="n">a</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And we expose a basic function <code class="language-plaintext highlighter-rouge">log</code> that don’t even do anything so it’s
a bit miss-named. Whatever, you’re not forced to use the concepts here,
you can do the same thing with a simple <code class="language-plaintext highlighter-rouge">&lt;Template&gt;</code> and documentation!
In addition, you shouldn’t use <em>Concepts</em> only to do that kind of stuff.
It will take a full dedicated article about that subject.</p>

<p>Then, once you’re done with your library, you can use it that way:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">A</span> <span class="p">{</span>
  <span class="n">A</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">a</span><span class="p">)</span><span class="o">:</span> <span class="n">str</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="p">{};</span>
  <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">str</span><span class="p">;</span>
<span class="p">};</span>

<span class="k">template</span><span class="o">&lt;</span><span class="p">&gt;</span>
<span class="k">struct</span> <span class="nc">trait_to_string</span><span class="o">&lt;</span><span class="n">A</span><span class="o">&gt;</span> <span class="p">{</span>
  <span class="k">static</span> <span class="k">const</span> <span class="kt">bool</span> <span class="n">impl</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
  <span class="k">static</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">to_string</span><span class="p">(</span><span class="k">const</span> <span class="n">A</span><span class="o">&amp;</span> <span class="n">self</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="n">str</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">};</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
  <span class="n">A</span> <span class="n">a</span><span class="p">(</span><span class="s">"hello world"</span><span class="p">);</span>
  <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">log</span><span class="p">(</span><span class="n">a</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>I’m agree, the flag isn’t really beautiful, it allow us to put a Concept
constraint and we’ll probably get a better way to define that. To be
honest, there is probably already a solution that I don’t know. :-D</p>

<p>However, look at the definition of the trait… Isn’t it <code class="language-plaintext highlighter-rouge">Rusty</code>?!</p>

<p>I leave you here for the moment! I’ll be back in next articles to be
more precise about <em>Concepts</em>. I promise to look attentively at that
flag too.</p>

<h2 id="conclusion">Conclusion</h2>
<p>Rust compiler do a lot of things for us to make the pattern efficient
and easy to use. In addition, there is a little thing that we learn the
last 20 years about hat pattern called the <em>Orphan rule</em>, and it’s
probably the reason why I didn’t heard much about <em>traits</em> in C++.</p>

<p>I really want to test the limits in C++ of the pattern! I’ll be back!</p>]]></content><author><name>Adrien Zinger</name></author><summary type="html"><![CDATA[The common point about these three words is that they all are _programming ideas_ and almost not related to any language feature. Those are the kinds of ideas that are the soul of modern programming.]]></summary></entry><entry><title type="html">Data propagation with unstructured P2P</title><link href="https://www.maybeuninit.com/2022/05/10/operation-propagation.html" rel="alternate" type="text/html" title="Data propagation with unstructured P2P" /><published>2022-05-10T00:00:00+00:00</published><updated>2022-05-10T00:00:00+00:00</updated><id>https://www.maybeuninit.com/2022/05/10/operation-propagation</id><content type="html" xml:base="https://www.maybeuninit.com/2022/05/10/operation-propagation.html"><![CDATA[<h2 id="data-propagation-with-unstructured-p2p">Data propagation with unstructured P2P</h2>
<p><span style="color: #A0A0A0">[2022-05-18] #p5Js #p2p</span></p>

<hr />

<div id="can" style="width:600px; height:400px;"></div>

<p>Consider a P2P network with, for any instant <em>T</em>, each node
are connected to perhaps 25% of the nodes (to reducing the global bandwidth).</p>

<p>Also consider that the network is open. A new node can spawn in the network, and connect itself to 25% of the nodes (ex: in a geographic zone).
Any nodes at <em>T</em> can create a new <em>data</em> to be propagated through
network.</p>

<p>Note: That kind of network can be any P2P model or any nodes
configuration. We can imagine a multitude of cell-phone sending notifications
to each others with bluetooth connections. Or a client based online video game
that use a kind of consensus, with a weak leader and weak node connections.
Or a blockchain network with poor connectivity between nodes.</p>

<p>How to propagate the information through the network?</p>

<h3 id="straightforward">Straightforward</h3>

<p>The simplest tactic is sending the data that we received to every
neighbors once. And send the data that we produce to every neighbor once.</p>

<p><img src="/assets/img/graph_id_send_workflow.svg" alt="workflow of a data propagation" /></p>

<p>The <em>“algorithm”</em> is very basic but works well with no surprise. But looking
at the workflow of an information. We understand that a node will receive
the information from a kind of random amount of distant nodes. And more
the network grow up, more he will receive a lot of useless batches of data.</p>

<p><img src="/assets/img/horrible_id_wf.svg" alt="hell of data propagation" /></p>

<p>In the worst case the data is really taking a lot of place in our bandwidth
😨</p>

<h3 id="solutions-of-accumulated-evidences">Solutions of accumulated evidences</h3>

<p>The solution cut the transfers of the data in two part, the first discussion
between the nodes contains only a hash of the data. And then, the distant node
choose by itself if getting the full buffer or not.</p>

<p>Sending the full body with the information is taking time and bandwidth because
of the size of that one. In fact, the straightforward tactic of propagation is
good enough for small data, but not for a large buffer.</p>

<p>So nodes are receiving hash/ids of the data and increment locally the number of times
a node say <em>“Hi! I get that data, by the way”</em>.</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// On receive a hash key, increment a counter in the `this.known`</span>
<span class="c1">// structure ('known' because we heard about that data)</span>
<span class="nx">insertOpKey</span><span class="p">(</span><span class="nx">key</span><span class="p">)</span> <span class="p">{</span>
    <span class="c1">// return if we already have the full data locally</span>
    <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">owned</span><span class="p">.</span><span class="nx">findIndex</span><span class="p">(</span><span class="nx">e</span> <span class="o">=&gt;</span> <span class="nx">e</span> <span class="o">==</span> <span class="nx">key</span><span class="p">)</span> <span class="o">&gt;</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>

    <span class="kd">const</span> <span class="nx">index</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">known</span><span class="p">.</span><span class="nx">findIndex</span><span class="p">(</span><span class="nx">e</span> <span class="o">=&gt;</span> <span class="nx">e</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">===</span> <span class="nx">key</span><span class="p">);</span>
    <span class="nx">index</span> <span class="o">===</span> <span class="o">-</span><span class="mi">1</span>
        <span class="p">?</span> <span class="k">this</span><span class="p">.</span><span class="nx">known</span><span class="p">.</span><span class="nx">push</span><span class="p">([</span><span class="nx">key</span><span class="p">,</span> <span class="mi">0</span><span class="p">])</span> <span class="c1">// create a counter</span>
        <span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">known</span><span class="p">[</span><span class="nx">index</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span><span class="o">++</span><span class="p">;</span> <span class="c1">// increment the counter</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">known</span><span class="p">.</span><span class="nx">sort</span><span class="p">((</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">a</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">&gt;</span> <span class="nx">b</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="p">},</span>
</code></pre></div></div>

<p>So, the last <code class="language-plaintext highlighter-rouge">sort</code> is very useful for the second and last part of the algorithm!
It gave me that strategical order.</p>

<p>The table <code class="language-plaintext highlighter-rouge">this.known</code> looks like that:</p>
<div style="font-size:30px; line-height:auto;">
<span style="font-size:20px;">youngest data (or fake)</span> &lt;&lt;&lt;&lt;&lt;&lt;
<br />
&gt;&gt;&gt;&gt;&gt;&gt; <span style="font-size:20px;">oldest data with a lot of replication (probably not a fake)</span>
</div>

<p>Actually, more we heard about a data, more it will be easy to find it. But we could also ask to the latest
senders of the ids directly when we want to get the data!</p>

<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">peek</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">known</span><span class="p">.</span><span class="nx">length</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>

    <span class="kd">const</span> <span class="nx">i</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">known</span><span class="p">.</span><span class="nx">pop</span><span class="p">();</span>
    <span class="c1">// the following two lines must be replaced with a logic</span>
    <span class="c1">// that "find" the data in your real network. Here I just</span>
    <span class="c1">// simulate that :-)</span>

    <span class="c1">// if (this.owned.contains(i[0])) return;</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">setStatus</span><span class="p">(</span><span class="nx">i</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
    <span class="k">this</span><span class="p">.</span><span class="nx">owned</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">i</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
<span class="p">},</span>
</code></pre></div></div>

<hr />

<h3 id="thanks">Thank’s!</h3>

<p>Thank you for reading! If you appreciate that little P2P introduction. You can
find the full code of the preview on my blog repository in the following paths:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">.</span>
├── assets
│   ├── js
│   │   ├── constants.js <span class="c"># some constants for the mocked network configuration</span>
│   │   ├── graphical.js <span class="c"># Drawing tools</span>
│   │   ├── node.js      <span class="c"># Nodes behaviors</span>
│   │   └── sketch.js    <span class="c"># p5js configuration and main loop</span>
</code></pre></div></div>]]></content><author><name>Adrien Zinger</name></author><summary type="html"><![CDATA[In a P2P network, the spread of an information is very important, especially with an open and unstructured network. However, with the popularity of the blockchain and decentralization, we have to also being resilient to attacks or to weak nodes connection and disconnection... Here I show how we can propagate efficiently with a simple algorithm.]]></summary></entry><entry><title type="html">Bootstrap a database in real time 1/4</title><link href="https://www.maybeuninit.com/2022/05/02/a-bootstrap-a-database-in-real-time.html" rel="alternate" type="text/html" title="Bootstrap a database in real time 1/4" /><published>2022-05-02T00:00:00+00:00</published><updated>2022-05-02T00:00:00+00:00</updated><id>https://www.maybeuninit.com/2022/05/02/a-bootstrap-a-database-in-real-time</id><content type="html" xml:base="https://www.maybeuninit.com/2022/05/02/a-bootstrap-a-database-in-real-time.html"><![CDATA[<h1 id="bootstrap-a-database-in-realtime">Bootstrap a database in realtime</h1>

<h2 id="advertisement">Advertisement</h2>

<p>The following articles are about a generic study of how we could bootstrap a
key-value database. I will not talk about SQLite and even less mongodb.</p>

<p>Instead, that article can be helpful (I hope so), if you’re working on a <em>P2P</em>
project where you manage a kind of data-replication/streaming between several
nodes.</p>

<h2 id="data-structures">Data structures</h2>

<p>The database can be seen as a data structure. The classical storage of data is
a kind o hashmap or a relational key-value structure. Hashmap are optimized to
be fast and very safe to use. But doesn’t respect the mandatory requirement of
a real-time streaming: <em>Ordering</em>.</p>

<h3 id="hashmap">Hashmap</h3>

<p>The function below will print the keys in the correct order. Because the
insertion will make a binary tree search before insertion, and doesn’t hash the
keys before insertion. A hashmap would have generated a random <em>Hasher</em> in the
execution, that can be considered as “sorted” because the iterator would give
the same key order, while we don’t stop the program.</p>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="k">mut</span> <span class="n">map</span> <span class="o">=</span> <span class="nn">HashMap</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
<span class="n">map</span><span class="nf">.insert</span><span class="p">(</span><span class="s">"a"</span><span class="p">,</span> <span class="s">"hello"</span><span class="p">);</span>
<span class="n">map</span><span class="nf">.insert</span><span class="p">(</span><span class="s">"b"</span><span class="p">,</span> <span class="s">"hello"</span><span class="p">);</span>
<span class="n">map</span><span class="nf">.insert</span><span class="p">(</span><span class="s">"c"</span><span class="p">,</span> <span class="s">"hello"</span><span class="p">);</span>
<span class="n">map</span><span class="nf">.insert</span><span class="p">(</span><span class="s">"d"</span><span class="p">,</span> <span class="s">"hello"</span><span class="p">);</span>
<span class="k">for</span> <span class="n">_</span> <span class="k">in</span> <span class="mi">0</span><span class="o">..</span><span class="mi">10</span> <span class="p">{</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">_value</span><span class="p">)</span> <span class="k">in</span> <span class="n">map</span><span class="nf">.clone</span><span class="p">()</span> <span class="p">{</span>
        <span class="nd">print!</span><span class="p">(</span><span class="s">"{key},"</span><span class="p">);</span> <span class="c1">// will print 10 times the keys in the same order</span>
    <span class="p">}</span>
    <span class="nd">println!</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>That said, when we generate and store the keys ourselves, and keep it in
another data store
the problem of ordering with the classical HashMap is solved. It is solved
because the order of the hashmap is now deterministic and the same for each
instances.</p>

<p>First, we need to bypass the Hasher implementation, and take the key as the
real hash. For a lot of efficiency reasons, the hashes have to respect some
specificities:</p>

<ul>
  <li>Having the same type.</li>
  <li>Being Sized. (size known at compile time)</li>
</ul>

<p>Now if you store the entries in a database, or, if you’re in a P2P behavior, in
another node that keep the data consistency. Every running instance of our
program will have the same key ordering.</p>

<p><em>Pro</em>: That situation is benefit, keys are <em>“prehashed”</em> and keeps order
consistency. The classical maps operations are as fast as possible.</p>

<p><em>Cons</em>: You should be careful with the hashing function, a little miss
is very difficult to find, and can have disastrous impacts on a bootstrap
algorithm.</p>

<h3 id="btreemap">BTreeMap</h3>

<p>In comparison to an HashMap, a BTreeMap:</p>
<ul>
  <li>creates a kind of binary tree</li>
  <li>has cheap reallocation</li>
  <li>is ordered by key</li>
</ul>

<div class="language-rust highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">let</span> <span class="k">mut</span> <span class="n">map</span> <span class="o">=</span> <span class="nn">std</span><span class="p">::</span><span class="nn">collections</span><span class="p">::</span><span class="nn">BTreeMap</span><span class="p">::</span><span class="nf">new</span><span class="p">();</span>
    <span class="n">map</span><span class="nf">.insert</span><span class="p">(</span><span class="s">"a"</span><span class="p">,</span> <span class="s">"hello"</span><span class="p">);</span>
    <span class="n">map</span><span class="nf">.insert</span><span class="p">(</span><span class="s">"b"</span><span class="p">,</span> <span class="s">"hello"</span><span class="p">);</span>
    <span class="n">map</span><span class="nf">.insert</span><span class="p">(</span><span class="s">"c"</span><span class="p">,</span> <span class="s">"hello"</span><span class="p">);</span>
    <span class="n">map</span><span class="nf">.insert</span><span class="p">(</span><span class="s">"d"</span><span class="p">,</span> <span class="s">"hello"</span><span class="p">);</span>
    <span class="k">for</span> <span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">_value</span><span class="p">)</span> <span class="k">in</span> <span class="n">map</span> <span class="p">{</span>
        <span class="nd">println!</span><span class="p">(</span><span class="s">"{key}"</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>A BTreeMap will always give the same order, mainly because there is no Hasher.
Basically, a BTreeMap is a good compromise between an HashMap and a Binary
tree. It takes advantage of memory pages to be fast, but <code class="language-plaintext highlighter-rouge">get</code> and <code class="language-plaintext highlighter-rouge">insert</code>
are always a search in a tree.</p>

<p><em>Pro</em>: We don’t have to maintain a hash function.</p>

<p><em>Cons</em>: This is a tree.</p>

<p><b><a href="/2022/05/02/b-bootstrap-a-database-in-real-time.html">solutions →</a></b></p>]]></content><author><name>Adrien Zinger</name></author><summary type="html"><![CDATA[Studying some theoretical bootstrap methods in a P2P network. Which are the data structures, introduction... 1/4]]></summary></entry></feed>