/2014-10-13T16:00:00+02:0032-bit Linux version for Marko Editor2014-10-13T16:00:00+02:002014-10-13T16:00:00+02:00Michael Munzerttag:None,2014-10-13:/blog/32-bit-linux-version-for-marko-editor<p>Hi guys,</p>
<p>the 32-bit Linux version is finally available. The build process is identical to the 64-bit version, so it's a <code>deb</code> package and was created on Ubuntu 14.04 LTS and has just Qt5 as dependencies.</p>
<p>Have fun. </p>Linux version for Marko Editor2014-10-08T14:35:00+02:002014-10-08T14:35:00+02:00Michael Munzerttag:None,2014-10-08:/blog/linux-version-for-marko-editor<p>Hi guys,</p>
<p>I finally got around to create a Linux version for Marko Editor. Currently there is only a <code>deb</code> package for 64bit systems. It was created on Ubuntu 14.04 LTS and has just Qt5 as dependencies.</p>
<p>I fixed some smaller issues on the way, so the other versions …</p><p>Hi guys,</p>
<p>I finally got around to create a Linux version for Marko Editor. Currently there is only a <code>deb</code> package for 64bit systems. It was created on Ubuntu 14.04 LTS and has just Qt5 as dependencies.</p>
<p>I fixed some smaller issues on the way, so the other versions are also updated.</p>
<p>Have fun. </p>Bug fixes for Marko Editor2014-10-02T14:00:00+02:002014-10-02T14:00:00+02:00Michael Munzerttag:None,2014-10-02:/blog/bug-fixes-for-marko-editor<p>Hi guys,</p>
<p>just a short heads up, there is a small bug fix release available for Marko Editor. Starting this version there is now an about dialog and an <em>official</em> version; I decided to be at 0.7.1 :-)</p>
<p>Have fun. </p>CriticsMarkup for Marko Editor2014-10-01T13:00:00+02:002014-10-01T13:00:00+02:00Michael Munzerttag:None,2014-10-01:/blog/criticsmarkup-for-marko-editor<p>Hi folks, </p>
<p>I'm happy to announce a new update for you. </p>
<p>The goal of Marko Editor is to allow fast and intuitive editing without getting distracted by markup or syntax. Therefore we don't need syntax highlighting for Markdown, and we can use colors to provide additional meaning for documents while …</p><p>Hi folks, </p>
<p>I'm happy to announce a new update for you. </p>
<p>The goal of Marko Editor is to allow fast and intuitive editing without getting distracted by markup or syntax. Therefore we don't need syntax highlighting for Markdown, and we can use colors to provide additional meaning for documents while maintaining a clean view.</p>
<p>Markdown doesn't offer support for colors, but the CriticsMarkup project provides reasoning and simple syntax for a few colors. Marko Editor now understands their <strong>addition</strong> (shortcut: <code>F1</code>), <strong>removal</strong> (<code>F2</code>), <strong>highlight</strong> (<code>F3</code>), <strong>comment</strong> (<code>F4</code>) and <strong>substitution</strong> (removal directly followed by addition) markup as inline formats.</p>
<p>Additionally it is now possible to have inline formats on headers and to insert horizontal rules (simply type <code>---</code> + <code>Return</code>, <code>Shift+Return</code> to omit the rule insertion).</p>
<p>Have fun and please tell me what you think :-)</p>Source view for Marko Editor2014-09-14T21:30:00+02:002014-09-14T21:30:00+02:00Michael Munzerttag:None,2014-09-14:/blog/source-view-for-marko-editor<p>Hi folks,</p>
<p>The first small update for Marko Editor is available.</p>
<p>You'll find an additional icon in the tool bar which allows to toggle between WYSIWYG and source view. Changing the source will also change the WYSIWYG content and vice versa.</p>
<p><a href="/index.html#download">Get it.</a></p>
<p>Have fun.</p>First release of Marko Editor2014-09-11T18:00:00+02:002014-09-11T18:00:00+02:00Michael Munzerttag:None,2014-09-11:/blog/first-release<p>Hi folks,</p>
<p>I'm happy to publicly release the first version of Marko Editor.</p>
<p>Marko Editor is a small desktop application which allows you to edit your Markdown files in a WYSIWYG manner. However, this is the first release and only the most used (from my point of view) Markdown elements …</p><p>Hi folks,</p>
<p>I'm happy to publicly release the first version of Marko Editor.</p>
<p>Marko Editor is a small desktop application which allows you to edit your Markdown files in a WYSIWYG manner. However, this is the first release and only the most used (from my point of view) Markdown elements are available.</p>
<p>Marko Editor may be used for free in private and commercial environments.</p>
<p><a href="/index.html">Read more and get it.</a></p>
<p>Have fun.</p>Signing and verifying a string with Crypto++2014-03-20T11:36:00+01:002014-03-20T11:36:00+01:00Michael Munzerttag:None,2014-03-20:/articles/cryptopp_sign_string<p>This small example shows how to verify the integrity of a message. We follow the digital signature algorithm (DSA) and generate a pair of keys, private and public (the public key is actually not unique). We get the signature by signing the message with the private key (which should never …</p><p>This small example shows how to verify the integrity of a message. We follow the digital signature algorithm (DSA) and generate a pair of keys, private and public (the public key is actually not unique). We get the signature by signing the message with the private key (which should never be shared). A recipient can check if the message is unmodified by using the signature and just a public key. However, the public key is not enough to change the message and sign it again.</p>
<p>The presented code uses C++ and the open source library <a href="http://www.cryptopp.com/">Crypto++</a>. Since the keys need to be embedded in text files, all cryptographic elements are converted to a hex representation. Crypto++ provides the necessary <a href="http://www.cryptopp.com/wiki">documentation</a> but it is quite some work putting the pieces together; so maybe this example will help someone.</p>
<p><strong>Additional reference:</strong> Some more theoretical background with a traditional (not judging!) implementation may be found on <a href="http://www.codeproject.com/Articles/99499/Implementation-of-the-Licensing-System-for-a-Softw">CodeProject</a>. The code presented here uses the pipeline API of Crypto++ which gives a cleaner result. </p>
<p><strong>Note:</strong> This code is just a technical demonstration and may not be good enough for a security relevant system.</p>
<p>For my purpose I use the Whirlpool hash, you might need a <a href="http://www.cryptopp.com/wiki/RSA_Cryptography#Signature_Schemes">different one</a>.</p>
<div class="highlight"><pre><span></span><code><span class="k">using</span> <span class="n">Signer</span> <span class="o">=</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">RSASS</span><span class="o"><</span><span class="n">CryptoPP</span><span class="o">::</span><span class="n">PSSR</span><span class="p">,</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">Whirlpool</span><span class="o">>::</span><span class="n">Signer</span><span class="p">;</span>
<span class="k">using</span> <span class="n">Verifier</span> <span class="o">=</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">RSASS</span><span class="o"><</span><span class="n">CryptoPP</span><span class="o">::</span><span class="n">PSSR</span><span class="p">,</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">Whirlpool</span><span class="o">>::</span><span class="n">Verifier</span><span class="p">;</span>
</code></pre></div>
<h2>Pipeline API</h2>
<p>From a technical point of view, the pipeline API might be the most interesting part. It supports the chaining of filters to model a data flow in a clean way. The flow starts at a <em>source</em> and ends in a <em>sink</em> while possibly passing multiple <em>filters</em>. Crypto++ supports this by providing a common interface for the relevant objects and by handling the lifetime of passed objects (<a href="http://www.cryptopp.com/wiki/Pipelining">Technical details</a>). A typical example in this code is</p>
<div class="highlight"><pre><span></span><code> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">StringSource</span> <span class="n">ss</span><span class="p">(</span><span class="n">aMessage</span><span class="p">,</span> <span class="nb">true</span><span class="p">,</span>
<span class="k">new</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">SignerFilter</span><span class="p">(</span><span class="n">rng</span><span class="p">,</span> <span class="n">signer</span><span class="p">,</span>
<span class="k">new</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">HexEncoder</span><span class="p">(</span>
<span class="k">new</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">StringSink</span><span class="p">(</span><span class="n">signature</span><span class="p">))));</span>
</code></pre></div>
<p>This line takes the content of <code>aMessage</code> and passes it to <code>CryptoPP::SignerFilter</code> (with additional arguments). The result of the filter is passed to <code>CryptoPP::HexEncoder</code> and finally the encoded result is passed to the variable <code>signature</code> by <code>CryptoPP::StringSink</code>. The equivalent code with the traditional API would be:</p>
<div class="highlight"><pre><span></span><code> <span class="kt">size_t</span> <span class="n">length</span> <span class="o">=</span> <span class="n">signer</span><span class="p">.</span><span class="n">MaxSignatureLength</span><span class="p">();</span>
<span class="n">CryptoPP</span><span class="o">::</span><span class="n">SecByteBlock</span> <span class="n">signatureRaw</span><span class="p">(</span><span class="n">length</span><span class="p">);</span>
<span class="c1">// sign message</span>
<span class="n">signer</span><span class="p">.</span><span class="n">SignMessage</span><span class="p">(</span><span class="n">rng</span><span class="p">,</span> <span class="p">(</span><span class="k">const</span> <span class="n">byte</span><span class="o">*</span><span class="p">)</span><span class="n">aMessage</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span>
<span class="n">aMessage</span><span class="p">.</span><span class="n">size</span><span class="p">(),</span> <span class="n">signatureRaw</span><span class="p">);</span>
<span class="c1">// hex encode signature</span>
<span class="n">CryptoPP</span><span class="o">::</span><span class="n">HexEncoder</span> <span class="n">encoder</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">signature</span><span class="p">;</span>
<span class="n">encoder</span><span class="p">.</span><span class="n">Attach</span><span class="p">(</span><span class="k">new</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">StringSink</span><span class="p">(</span><span class="n">signature</span><span class="p">));</span>
<span class="n">encoder</span><span class="p">.</span><span class="n">Put</span><span class="p">(</span><span class="n">signatureRaw</span><span class="p">.</span><span class="n">data</span><span class="p">(),</span> <span class="n">signatureRaw</span><span class="p">.</span><span class="n">size</span><span class="p">());</span>
<span class="n">encoder</span><span class="p">.</span><span class="n">MessageEnd</span><span class="p">();</span>
</code></pre></div>
<h2>Complete example</h2>
<p><code>crypto.h</code></p>
<div class="highlight"><pre><span></span><code><span class="cp">#ifndef CRYPTO_H</span>
<span class="cp">#define CRYPTO_H</span>
<span class="cp">#pragma GCC diagnostic push</span>
<span class="cp">#pragma GCC diagnostic ignored "-Wunknown-pragmas"</span>
<span class="cp">#pragma GCC diagnostic ignored "-Wunused-variable"</span>
<span class="cp">#pragma GCC diagnostic ignored "-Wunused-function"</span>
<span class="cp">#pragma GCC diagnostic ignored "-Wunused-parameter"</span>
<span class="cp">#pragma GCC diagnostic ignored "-Wpragmas"</span>
<span class="cp">#pragma GCC diagnostic ignored "-Wextra"</span>
<span class="cp">#include</span> <span class="cpf"><hex.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><osrng.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><pssr.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><rsa.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><whrlpool.h></span><span class="cp"></span>
<span class="cp">#pragma GCC diagnostic pop</span>
<span class="cp">#include</span> <span class="cpf"><string></span><span class="cp"></span>
<span class="c1">// see http://www.cryptopp.com/wiki/RSA</span>
<span class="k">struct</span> <span class="nc">KeyPairHex</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">publicKey</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">privateKey</span><span class="p">;</span>
<span class="p">};</span>
<span class="k">using</span> <span class="n">Signer</span> <span class="o">=</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">RSASS</span><span class="o"><</span><span class="n">CryptoPP</span><span class="o">::</span><span class="n">PSSR</span><span class="p">,</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">Whirlpool</span><span class="o">>::</span><span class="n">Signer</span><span class="p">;</span>
<span class="k">using</span> <span class="n">Verifier</span> <span class="o">=</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">RSASS</span><span class="o"><</span><span class="n">CryptoPP</span><span class="o">::</span><span class="n">PSSR</span><span class="p">,</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">Whirlpool</span><span class="o">>::</span><span class="n">Verifier</span><span class="p">;</span>
<span class="c1">//==============================================================================</span>
<span class="kr">inline</span> <span class="n">KeyPairHex</span> <span class="n">RsaGenerateHexKeyPair</span><span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">aKeySize</span><span class="p">)</span> <span class="p">{</span>
<span class="n">KeyPairHex</span> <span class="n">keyPair</span><span class="p">;</span>
<span class="c1">// PGP Random Pool-like generator</span>
<span class="n">CryptoPP</span><span class="o">::</span><span class="n">AutoSeededRandomPool</span> <span class="n">rng</span><span class="p">;</span>
<span class="c1">// generate keys</span>
<span class="n">CryptoPP</span><span class="o">::</span><span class="n">RSA</span><span class="o">::</span><span class="n">PrivateKey</span> <span class="n">privateKey</span><span class="p">;</span>
<span class="n">privateKey</span><span class="p">.</span><span class="n">GenerateRandomWithKeySize</span><span class="p">(</span><span class="n">rng</span><span class="p">,</span> <span class="n">aKeySize</span><span class="p">);</span>
<span class="n">CryptoPP</span><span class="o">::</span><span class="n">RSA</span><span class="o">::</span><span class="n">PublicKey</span> <span class="n">publicKey</span><span class="p">(</span><span class="n">privateKey</span><span class="p">);</span>
<span class="c1">// save keys</span>
<span class="n">publicKey</span><span class="p">.</span><span class="n">Save</span><span class="p">(</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">HexEncoder</span><span class="p">(</span>
<span class="k">new</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">StringSink</span><span class="p">(</span><span class="n">keyPair</span><span class="p">.</span><span class="n">publicKey</span><span class="p">)).</span><span class="n">Ref</span><span class="p">());</span>
<span class="n">privateKey</span><span class="p">.</span><span class="n">Save</span><span class="p">(</span><span class="n">CryptoPP</span><span class="o">::</span><span class="n">HexEncoder</span><span class="p">(</span>
<span class="k">new</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">StringSink</span><span class="p">(</span><span class="n">keyPair</span><span class="p">.</span><span class="n">privateKey</span><span class="p">)).</span><span class="n">Ref</span><span class="p">());</span>
<span class="k">return</span> <span class="n">keyPair</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">//==============================================================================</span>
<span class="kr">inline</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">RsaSignString</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="o">&</span><span class="n">aPrivateKeyStrHex</span><span class="p">,</span>
<span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="o">&</span><span class="n">aMessage</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// decode and load private key (using pipeline)</span>
<span class="n">CryptoPP</span><span class="o">::</span><span class="n">RSA</span><span class="o">::</span><span class="n">PrivateKey</span> <span class="n">privateKey</span><span class="p">;</span>
<span class="n">privateKey</span><span class="p">.</span><span class="n">Load</span><span class="p">(</span><span class="n">CryptoPP</span><span class="o">::</span><span class="n">StringSource</span><span class="p">(</span><span class="n">aPrivateKeyStrHex</span><span class="p">,</span> <span class="nb">true</span><span class="p">,</span>
<span class="k">new</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">HexDecoder</span><span class="p">()).</span><span class="n">Ref</span><span class="p">());</span>
<span class="c1">// sign message</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">signature</span><span class="p">;</span>
<span class="n">Signer</span> <span class="nf">signer</span><span class="p">(</span><span class="n">privateKey</span><span class="p">);</span>
<span class="n">CryptoPP</span><span class="o">::</span><span class="n">AutoSeededRandomPool</span> <span class="n">rng</span><span class="p">;</span>
<span class="n">CryptoPP</span><span class="o">::</span><span class="n">StringSource</span> <span class="n">ss</span><span class="p">(</span><span class="n">aMessage</span><span class="p">,</span> <span class="nb">true</span><span class="p">,</span>
<span class="k">new</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">SignerFilter</span><span class="p">(</span><span class="n">rng</span><span class="p">,</span> <span class="n">signer</span><span class="p">,</span>
<span class="k">new</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">HexEncoder</span><span class="p">(</span>
<span class="k">new</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">StringSink</span><span class="p">(</span><span class="n">signature</span><span class="p">))));</span>
<span class="k">return</span> <span class="n">signature</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">//==============================================================================</span>
<span class="kr">inline</span> <span class="kt">bool</span> <span class="n">RsaVerifyString</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="o">&</span><span class="n">aPublicKeyStrHex</span><span class="p">,</span>
<span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="o">&</span><span class="n">aMessage</span><span class="p">,</span>
<span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="o">&</span><span class="n">aSignatureStrHex</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// decode and load public key (using pipeline)</span>
<span class="n">CryptoPP</span><span class="o">::</span><span class="n">RSA</span><span class="o">::</span><span class="n">PublicKey</span> <span class="n">publicKey</span><span class="p">;</span>
<span class="n">publicKey</span><span class="p">.</span><span class="n">Load</span><span class="p">(</span><span class="n">CryptoPP</span><span class="o">::</span><span class="n">StringSource</span><span class="p">(</span><span class="n">aPublicKeyStrHex</span><span class="p">,</span> <span class="nb">true</span><span class="p">,</span>
<span class="k">new</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">HexDecoder</span><span class="p">()).</span><span class="n">Ref</span><span class="p">());</span>
<span class="c1">// decode signature</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">decodedSignature</span><span class="p">;</span>
<span class="n">CryptoPP</span><span class="o">::</span><span class="n">StringSource</span> <span class="n">ss</span><span class="p">(</span><span class="n">aSignatureStrHex</span><span class="p">,</span> <span class="nb">true</span><span class="p">,</span>
<span class="k">new</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">HexDecoder</span><span class="p">(</span>
<span class="k">new</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">StringSink</span><span class="p">(</span><span class="n">decodedSignature</span><span class="p">)));</span>
<span class="c1">// verify message</span>
<span class="kt">bool</span> <span class="n">result</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
<span class="n">Verifier</span> <span class="nf">verifier</span><span class="p">(</span><span class="n">publicKey</span><span class="p">);</span>
<span class="n">CryptoPP</span><span class="o">::</span><span class="n">StringSource</span> <span class="n">ss2</span><span class="p">(</span><span class="n">decodedSignature</span> <span class="o">+</span> <span class="n">aMessage</span><span class="p">,</span> <span class="nb">true</span><span class="p">,</span>
<span class="k">new</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">SignatureVerificationFilter</span><span class="p">(</span><span class="n">verifier</span><span class="p">,</span>
<span class="k">new</span> <span class="n">CryptoPP</span><span class="o">::</span><span class="n">ArraySink</span><span class="p">((</span><span class="n">byte</span><span class="o">*</span><span class="p">)</span><span class="o">&</span><span class="n">result</span><span class="p">,</span>
<span class="k">sizeof</span><span class="p">(</span><span class="n">result</span><span class="p">))));</span>
<span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>
<span class="cp">#endif </span><span class="c1">// CRYPTO_H</span>
</code></pre></div>
<p><code>main.cpp</code></p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span> <span class="cpf">"crypto.h"</span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><iostream></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><string></span><span class="cp"></span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="p">)</span> <span class="p">{</span>
<span class="k">auto</span> <span class="n">keys</span> <span class="o">=</span> <span class="n">RsaGenerateHexKeyPair</span><span class="p">(</span><span class="mi">3072</span><span class="p">);</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Private key: "</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span> <span class="o"><<</span> <span class="n">keys</span><span class="p">.</span><span class="n">privateKey</span> <span class="o"><<</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Public key: "</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span> <span class="o"><<</span> <span class="n">keys</span><span class="p">.</span><span class="n">publicKey</span> <span class="o"><<</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">message</span><span class="p">(</span><span class="s">"secret message"</span><span class="p">);</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Message:"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">message</span> <span class="o"><<</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="c1">// generate a signature for the message</span>
<span class="k">auto</span> <span class="n">signature</span><span class="p">(</span><span class="n">RsaSignString</span><span class="p">(</span><span class="n">keys</span><span class="p">.</span><span class="n">privateKey</span><span class="p">,</span> <span class="n">message</span><span class="p">));</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Signature:"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">signature</span> <span class="o"><<</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="c1">// verify signature against public key</span>
<span class="k">if</span> <span class="p">(</span><span class="n">RsaVerifyString</span><span class="p">(</span><span class="n">keys</span><span class="p">.</span><span class="n">publicKey</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">signature</span><span class="p">))</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Signatue valid."</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Signatue invalid."</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>How to store anything in Boost PropertyTree2013-12-11T01:56:00+01:002013-12-11T01:56:00+01:00Michael Munzerttag:None,2013-12-11:/articles/property_tree_store_anything<p>One of the fundamental data structures in information processing is the tree, to model hierarchical data. Although we have many standardized containers in C++, a tree structure is still missing. Of course, there are several different libraries which provide this feature in different facets. For my current work I am …</p><p>One of the fundamental data structures in information processing is the tree, to model hierarchical data. Although we have many standardized containers in C++, a tree structure is still missing. Of course, there are several different libraries which provide this feature in different facets. For my current work I am using Boost PropertyTree and in this article I want to describe a small enhancement to it.</p>
<p>Boost PropertyTree delivers some quite unique features compared to other tree libraries. For instance it has a flexible leaf type built in, i.e. the data stored in different leaves may have different types. Though one could add this feature to other trees with a variant type in the leaves, but this adds another level of indirection. Another very nice feature is the parsing and generation of XML, JSON, INI and Info files. So, for simple data storing and reading tasks Boost PropertyTree provides everything out of the box.</p>
<p>Once you like to work with this tree structure, you might use it in other contexts as simple data handling. That leaves may hold different types comes in very handy, but one realizes quite soon, they may only hold types, which stream to and from <code>string</code> (at least if you use the default <code>ptree</code> with standard data type <code>string</code>). So, we could provide the two stream operators for our data type, if we were free to add them (they could already be in use for user output etc.). </p>
<p>Luckily the authors help us in this respect and provide a customization point for PropertyTree, namely the <code>struct translator_between</code>. Next we need to get a fast and reliable string storage for custom types like:</p>
<div class="highlight"><pre><span></span><code><span class="k">struct</span> <span class="nc">person_t</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">prename</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span><span class="p">;</span>
<span class="p">};</span>
<span class="k">struct</span> <span class="nc">entry_t</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">key</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">value</span><span class="p">;</span>
<span class="p">};</span>
<span class="k">struct</span> <span class="nc">data_t</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="n">entry_t</span><span class="o">></span> <span class="n">entries</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div>
<p>Manually writing and parsing might still be ok for <code>person_t</code> but it gets quite cumbersome for <code>data_t</code>, even when using Boost Spirit. Again we rely on a solid solution by using Boost Serialization for this task. Since you might not be able to alter the type definitions, Boost Serialization allows to add the serialization feature externally to the types:</p>
<div class="highlight"><pre><span></span><code><span class="k">namespace</span> <span class="n">boost</span> <span class="p">{</span>
<span class="k">namespace</span> <span class="n">serialization</span> <span class="p">{</span>
<span class="k">template</span><span class="o"><</span><span class="k">class</span> <span class="nc">Archive</span><span class="o">></span>
<span class="kt">void</span> <span class="n">serialize</span><span class="p">(</span><span class="n">Archive</span> <span class="o">&</span> <span class="n">ar</span><span class="p">,</span> <span class="n">person_t</span> <span class="o">&</span> <span class="n">obj</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
<span class="n">ar</span> <span class="o">&</span> <span class="n">obj</span><span class="p">.</span><span class="n">name</span><span class="p">;</span>
<span class="n">ar</span> <span class="o">&</span> <span class="n">obj</span><span class="p">.</span><span class="n">prename</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">template</span><span class="o"><</span><span class="k">class</span> <span class="nc">Archive</span><span class="o">></span>
<span class="kt">void</span> <span class="n">serialize</span><span class="p">(</span><span class="n">Archive</span> <span class="o">&</span> <span class="n">ar</span><span class="p">,</span> <span class="n">entry_t</span> <span class="o">&</span> <span class="n">obj</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
<span class="n">ar</span> <span class="o">&</span> <span class="n">obj</span><span class="p">.</span><span class="n">key</span><span class="p">;</span>
<span class="n">ar</span> <span class="o">&</span> <span class="n">obj</span><span class="p">.</span><span class="n">value</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">template</span><span class="o"><</span><span class="k">class</span> <span class="nc">Archive</span><span class="o">></span>
<span class="kt">void</span> <span class="n">serialize</span><span class="p">(</span><span class="n">Archive</span> <span class="o">&</span> <span class="n">ar</span><span class="p">,</span> <span class="n">data_t</span> <span class="o">&</span> <span class="n">obj</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
<span class="n">ar</span> <span class="o">&</span> <span class="n">obj</span><span class="p">.</span><span class="n">name</span><span class="p">;</span>
<span class="n">ar</span> <span class="o">&</span> <span class="n">obj</span><span class="p">.</span><span class="n">entries</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span> <span class="c1">// namespace serialization</span>
<span class="p">}</span> <span class="c1">// namespace boost</span>
</code></pre></div>
<p>However, we need to tell our PropertyTree that it should use the serialization if available. As said we specialize the <code>struct translator_between</code> template.</p>
<div class="highlight"><pre><span></span><code> <span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">string_type</span><span class="p">;</span>
<span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="nc">T</span><span class="o">></span>
<span class="k">struct</span> <span class="nc">translator_between</span><span class="o"><</span><span class="n">string_type</span><span class="p">,</span> <span class="n">T</span><span class="o">></span> <span class="p">{</span>
<span class="k">typedef</span> <span class="n">SerializationTranslator</span><span class="o"><</span><span class="n">string_type</span><span class="p">,</span> <span class="n">T</span><span class="o">></span> <span class="n">type</span><span class="p">;</span>
<span class="p">};</span>
<span class="k">template</span><span class="o"><></span>
<span class="k">struct</span> <span class="nc">translator_between</span><span class="o"><</span><span class="n">string_type</span><span class="p">,</span> <span class="n">string_type</span><span class="o">></span> <span class="p">{</span>
<span class="k">typedef</span> <span class="n">id_translator</span><span class="o"><</span><span class="n">string_type</span><span class="o">></span> <span class="n">type</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div>
<p>This tells Boost PropertyTree, that it finds a translator type <code>SerializationTranslator</code> somewhere. We get some compiling problems because there are already some <code>translator_between</code> specializations available, and the compiler cannot figure out which to use for <code>string</code>. To get around that, we specialize again for our chosen <code>string_type</code>. You have to change the <code>string_type</code> accordingly if you're using a different string data type. To proceed we need to provide the translator:</p>
<div class="highlight"><pre><span></span><code> <span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="nc">String</span><span class="p">,</span> <span class="k">typename</span> <span class="nc">T</span><span class="o">></span>
<span class="k">struct</span> <span class="nc">SerializationTranslator</span> <span class="p">{</span>
<span class="k">typedef</span> <span class="n">String</span> <span class="n">internal_type</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">T</span> <span class="n">external_type</span><span class="p">;</span>
<span class="n">boost</span><span class="o">::</span><span class="n">optional</span><span class="o"><</span><span class="n">external_type</span><span class="o">></span> <span class="n">get_value</span><span class="p">(</span><span class="k">const</span> <span class="n">internal_type</span><span class="o">&</span> <span class="n">str</span><span class="p">);</span>
<span class="n">boost</span><span class="o">::</span><span class="n">optional</span><span class="o"><</span><span class="n">internal_type</span><span class="o">></span> <span class="n">put_value</span><span class="p">(</span><span class="k">const</span> <span class="n">external_type</span><span class="o">&</span> <span class="n">obj</span><span class="p">);</span>
<span class="p">};</span>
</code></pre></div>
<p>We are providing a set and a get method, but the implementation is a little involved. There are a view points we need to handle:</p>
<ul>
<li>Boost PropertyTree stores fundamental types by using their stream operators. This gives a short (no boiler plate) and human readable string representation.</li>
<li>Boost Serialization stores fundamental types automatically also by using the stream operators. However, the serialization is longer then the string and not human readable.</li>
<li>Boost PropertyTree might be used to read or write files to disk; it would be nice to have those as clean as possible. So, we should not use Boost Serialization for fundamental types.</li>
<li>For custom types, we might already have stream operators defined. It is quite likely that those are not build to store and restore values, but to communicate with the user. So, we won't use those.</li>
<li>Finally, to store a custom type in the tree we want to have a serialization to have it as type safe as possible.</li>
</ul>
<div class="highlight"><pre><span></span><code> <span class="n">boost</span><span class="o">::</span><span class="n">optional</span><span class="o"><</span><span class="n">external_type</span><span class="o">></span> <span class="n">get_value</span><span class="p">(</span><span class="k">const</span> <span class="n">internal_type</span><span class="o">&</span> <span class="n">str</span><span class="p">)</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">istringstream</span> <span class="n">stream</span><span class="p">(</span><span class="n">str</span><span class="p">);</span>
<span class="n">external_type</span> <span class="n">result</span><span class="p">;</span>
<span class="n">istream</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">stream</span><span class="p">.</span><span class="n">rdstate</span><span class="p">()</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">ios</span><span class="o">::</span><span class="n">failbit</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">boost</span><span class="o">::</span><span class="n">none</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">boost</span><span class="o">::</span><span class="n">optional</span><span class="o"><</span><span class="n">internal_type</span><span class="o">></span> <span class="n">put_value</span><span class="p">(</span><span class="k">const</span> <span class="n">external_type</span><span class="o">&</span> <span class="n">obj</span><span class="p">)</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">ostringstream</span> <span class="n">result</span><span class="p">;</span>
<span class="n">ostream</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">obj</span><span class="p">);</span>
<span class="k">return</span> <span class="n">result</span><span class="p">.</span><span class="n">str</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">private</span><span class="o">:</span>
<span class="c1">//--------------------------------------</span>
<span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="nc">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="o">=</span> <span class="k">typename</span> <span class="nc">std</span><span class="o">::</span><span class="n">enable_if</span><span class="o"><</span>
<span class="n">std</span><span class="o">::</span><span class="n">is_assignable</span><span class="o"><</span><span class="n">internal_type</span><span class="p">,</span> <span class="n">Object</span><span class="o">>::</span><span class="n">value</span><span class="o">>::</span><span class="n">type</span><span class="o">></span>
<span class="k">static</span> <span class="k">auto</span> <span class="n">ostream</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">ostream</span><span class="o">&</span> <span class="n">o</span><span class="p">,</span> <span class="n">Object</span> <span class="k">const</span><span class="o">&</span> <span class="n">obj</span><span class="p">)</span>
<span class="o">-></span> <span class="k">decltype</span><span class="p">(</span><span class="n">o</span> <span class="o"><<</span> <span class="n">obj</span><span class="p">,</span> <span class="kt">void</span><span class="p">())</span> <span class="p">{</span>
<span class="n">o</span> <span class="o"><<</span> <span class="n">obj</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="nc">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="o">=</span> <span class="k">typename</span> <span class="nc">std</span><span class="o">::</span><span class="n">enable_if</span><span class="o"><</span>
<span class="o">!</span><span class="n">std</span><span class="o">::</span><span class="n">is_assignable</span><span class="o"><</span><span class="n">internal_type</span><span class="p">,</span> <span class="n">Object</span><span class="o">>::</span><span class="n">value</span><span class="o">>::</span><span class="n">type</span><span class="o">></span>
<span class="k">static</span> <span class="k">auto</span> <span class="n">ostream</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">ostream</span><span class="o">&</span> <span class="n">o</span><span class="p">,</span> <span class="n">Object</span> <span class="k">const</span><span class="o">&</span> <span class="n">obj</span><span class="p">)</span>
<span class="o">-></span> <span class="k">decltype</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">serialization</span><span class="o">::</span><span class="n">serialize</span><span class="o"><</span><span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">binary_oarchive</span><span class="o">></span><span class="p">(</span>
<span class="n">std</span><span class="o">::</span><span class="n">declval</span><span class="o"><</span><span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">binary_oarchive</span><span class="o">&></span><span class="p">(),</span> <span class="n">obj</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="kt">void</span><span class="p">())</span> <span class="p">{</span>
<span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">binary_oarchive</span> <span class="n">oa</span><span class="p">(</span><span class="n">o</span><span class="p">);</span>
<span class="n">oa</span> <span class="o"><<</span> <span class="n">obj</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">//--------------------------------------</span>
<span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="nc">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="o">=</span> <span class="k">typename</span> <span class="nc">std</span><span class="o">::</span><span class="n">enable_if</span><span class="o"><</span>
<span class="n">std</span><span class="o">::</span><span class="n">is_assignable</span><span class="o"><</span><span class="n">internal_type</span><span class="p">,</span> <span class="n">Object</span><span class="o">>::</span><span class="n">value</span><span class="o">>::</span><span class="n">type</span><span class="o">></span>
<span class="k">static</span> <span class="k">auto</span> <span class="n">istream</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">istream</span><span class="o">&</span> <span class="n">i</span><span class="p">,</span> <span class="n">Object</span><span class="o">&</span> <span class="n">obj</span><span class="p">)</span>
<span class="o">-></span> <span class="k">decltype</span><span class="p">(</span><span class="n">i</span> <span class="o">>></span> <span class="n">obj</span><span class="p">,</span> <span class="kt">void</span><span class="p">())</span> <span class="p">{</span>
<span class="n">i</span> <span class="o">>></span> <span class="n">obj</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="nc">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="o">=</span> <span class="k">typename</span> <span class="nc">std</span><span class="o">::</span><span class="n">enable_if</span><span class="o"><</span>
<span class="o">!</span><span class="n">std</span><span class="o">::</span><span class="n">is_assignable</span><span class="o"><</span><span class="n">internal_type</span><span class="p">,</span> <span class="n">Object</span><span class="o">>::</span><span class="n">value</span><span class="o">>::</span><span class="n">type</span><span class="o">></span>
<span class="k">static</span> <span class="k">auto</span> <span class="n">istream</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">istream</span><span class="o">&</span> <span class="n">i</span><span class="p">,</span> <span class="n">Object</span><span class="o">&</span> <span class="n">obj</span><span class="p">)</span>
<span class="o">-></span> <span class="k">decltype</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">serialization</span><span class="o">::</span><span class="n">serialize</span><span class="o"><</span><span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">binary_iarchive</span><span class="o">></span><span class="p">(</span>
<span class="n">std</span><span class="o">::</span><span class="n">declval</span><span class="o"><</span><span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">binary_iarchive</span><span class="o">&></span><span class="p">(),</span> <span class="n">obj</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="kt">void</span><span class="p">())</span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">binary_iarchive</span> <span class="n">ia</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
<span class="n">ia</span> <span class="o">>></span> <span class="n">obj</span><span class="p">;</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">archive_exception</span><span class="p">)</span> <span class="p">{</span>
<span class="n">i</span><span class="p">.</span><span class="n">setstate</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">ios</span><span class="o">::</span><span class="n">failbit</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">//--------------------------------------</span>
<span class="p">};</span>
</code></pre></div>
<p>We provide in each stream direction two functions. At most one of them is available for a given type, since the <code>std::enable_if</code> is complementary. In the enable if we check if a <code>std::string</code> could be constructed from the given type. This is true for the fundamental types and handles the stream operators for custom types. Additionally we enforce the existence of <code>boost::serialization::serialize</code> for custom types, which gives nicer compiler errors, if we try to store a custom type without serialization. </p>
<p>That is basically it. For each new type just add the corresponding <code>serialize</code> method and you are good to go.</p>
<h2>Complete example</h2>
<p>Here is the full example to play: </p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span> <span class="cpf"><boost/property_tree/ptree.hpp></span><span class="cp"></span>
<span class="k">namespace</span> <span class="n">pt</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">property_tree</span><span class="p">;</span>
<span class="cp">#include</span> <span class="cpf"><boost/archive/binary_oarchive.hpp></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><boost/archive/binary_iarchive.hpp></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><boost/serialization/vector.hpp></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><iostream></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><string></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><vector></span><span class="cp"></span>
<span class="c1">//==============================================================================</span>
<span class="k">struct</span> <span class="nc">person_t</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">prename</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span><span class="p">;</span>
<span class="p">};</span>
<span class="k">struct</span> <span class="nc">entry_t</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">key</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">value</span><span class="p">;</span>
<span class="p">};</span>
<span class="k">struct</span> <span class="nc">data_t</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">name</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="n">entry_t</span><span class="o">></span> <span class="n">entries</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">//--------------------------------------</span>
<span class="kr">inline</span> <span class="n">std</span><span class="o">::</span><span class="n">ostream</span><span class="o">&</span> <span class="k">operator</span><span class="o"><<</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">ostream</span> <span class="o">&</span><span class="n">o</span><span class="p">,</span> <span class="n">person_t</span> <span class="k">const</span><span class="o">&</span> <span class="n">obj</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">o</span> <span class="o"><<</span> <span class="n">obj</span><span class="p">.</span><span class="n">prename</span> <span class="o"><<</span> <span class="s">" "</span> <span class="o"><<</span> <span class="n">obj</span><span class="p">.</span><span class="n">name</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">//--------------------------------------</span>
<span class="k">namespace</span> <span class="n">boost</span> <span class="p">{</span>
<span class="k">namespace</span> <span class="n">serialization</span> <span class="p">{</span>
<span class="k">template</span><span class="o"><</span><span class="k">class</span> <span class="nc">Archive</span><span class="o">></span>
<span class="kt">void</span> <span class="n">serialize</span><span class="p">(</span><span class="n">Archive</span> <span class="o">&</span> <span class="n">ar</span><span class="p">,</span> <span class="n">person_t</span> <span class="o">&</span> <span class="n">obj</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
<span class="n">ar</span> <span class="o">&</span> <span class="n">obj</span><span class="p">.</span><span class="n">name</span><span class="p">;</span>
<span class="n">ar</span> <span class="o">&</span> <span class="n">obj</span><span class="p">.</span><span class="n">prename</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">template</span><span class="o"><</span><span class="k">class</span> <span class="nc">Archive</span><span class="o">></span>
<span class="kt">void</span> <span class="n">serialize</span><span class="p">(</span><span class="n">Archive</span> <span class="o">&</span> <span class="n">ar</span><span class="p">,</span> <span class="n">entry_t</span> <span class="o">&</span> <span class="n">obj</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
<span class="n">ar</span> <span class="o">&</span> <span class="n">obj</span><span class="p">.</span><span class="n">key</span><span class="p">;</span>
<span class="n">ar</span> <span class="o">&</span> <span class="n">obj</span><span class="p">.</span><span class="n">value</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">template</span><span class="o"><</span><span class="k">class</span> <span class="nc">Archive</span><span class="o">></span>
<span class="kt">void</span> <span class="n">serialize</span><span class="p">(</span><span class="n">Archive</span> <span class="o">&</span> <span class="n">ar</span><span class="p">,</span> <span class="n">data_t</span> <span class="o">&</span> <span class="n">obj</span><span class="p">,</span> <span class="k">const</span> <span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span> <span class="p">{</span>
<span class="n">ar</span> <span class="o">&</span> <span class="n">obj</span><span class="p">.</span><span class="n">name</span><span class="p">;</span>
<span class="n">ar</span> <span class="o">&</span> <span class="n">obj</span><span class="p">.</span><span class="n">entries</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span> <span class="c1">// namespace serialization</span>
<span class="p">}</span> <span class="c1">// namespace boost</span>
<span class="c1">//==============================================================================</span>
<span class="k">namespace</span> <span class="n">boost</span> <span class="p">{</span>
<span class="k">namespace</span> <span class="n">property_tree</span> <span class="p">{</span>
<span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="nc">String</span><span class="p">,</span> <span class="k">typename</span> <span class="nc">T</span><span class="o">></span>
<span class="k">struct</span> <span class="nc">SerializationTranslator</span> <span class="p">{</span>
<span class="k">typedef</span> <span class="n">String</span> <span class="n">internal_type</span><span class="p">;</span>
<span class="k">typedef</span> <span class="n">T</span> <span class="n">external_type</span><span class="p">;</span>
<span class="n">boost</span><span class="o">::</span><span class="n">optional</span><span class="o"><</span><span class="n">external_type</span><span class="o">></span> <span class="n">get_value</span><span class="p">(</span><span class="k">const</span> <span class="n">internal_type</span><span class="o">&</span> <span class="n">str</span><span class="p">)</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">istringstream</span> <span class="n">stream</span><span class="p">(</span><span class="n">str</span><span class="p">);</span>
<span class="n">external_type</span> <span class="n">result</span><span class="p">;</span>
<span class="n">istream</span><span class="p">(</span><span class="n">stream</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">stream</span><span class="p">.</span><span class="n">rdstate</span><span class="p">()</span> <span class="o">==</span> <span class="n">std</span><span class="o">::</span><span class="n">ios</span><span class="o">::</span><span class="n">failbit</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">boost</span><span class="o">::</span><span class="n">none</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">boost</span><span class="o">::</span><span class="n">optional</span><span class="o"><</span><span class="n">internal_type</span><span class="o">></span> <span class="n">put_value</span><span class="p">(</span><span class="k">const</span> <span class="n">external_type</span><span class="o">&</span> <span class="n">obj</span><span class="p">)</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">ostringstream</span> <span class="n">result</span><span class="p">;</span>
<span class="n">ostream</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">obj</span><span class="p">);</span>
<span class="k">return</span> <span class="n">result</span><span class="p">.</span><span class="n">str</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">private</span><span class="o">:</span>
<span class="c1">//--------------------------------------</span>
<span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="nc">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="o">=</span> <span class="k">typename</span> <span class="nc">std</span><span class="o">::</span><span class="n">enable_if</span><span class="o"><</span>
<span class="n">std</span><span class="o">::</span><span class="n">is_assignable</span><span class="o"><</span><span class="n">internal_type</span><span class="p">,</span> <span class="n">Object</span><span class="o">>::</span><span class="n">value</span><span class="o">>::</span><span class="n">type</span><span class="o">></span>
<span class="k">static</span> <span class="k">auto</span> <span class="n">ostream</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">ostream</span><span class="o">&</span> <span class="n">o</span><span class="p">,</span> <span class="n">Object</span> <span class="k">const</span><span class="o">&</span> <span class="n">obj</span><span class="p">)</span>
<span class="o">-></span> <span class="k">decltype</span><span class="p">(</span><span class="n">o</span> <span class="o"><<</span> <span class="n">obj</span><span class="p">,</span> <span class="kt">void</span><span class="p">())</span> <span class="p">{</span>
<span class="n">o</span> <span class="o"><<</span> <span class="n">obj</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="nc">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="o">=</span> <span class="k">typename</span> <span class="nc">std</span><span class="o">::</span><span class="n">enable_if</span><span class="o"><</span>
<span class="o">!</span><span class="n">std</span><span class="o">::</span><span class="n">is_assignable</span><span class="o"><</span><span class="n">internal_type</span><span class="p">,</span> <span class="n">Object</span><span class="o">>::</span><span class="n">value</span><span class="o">>::</span><span class="n">type</span><span class="o">></span>
<span class="k">static</span> <span class="k">auto</span> <span class="n">ostream</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">ostream</span><span class="o">&</span> <span class="n">o</span><span class="p">,</span> <span class="n">Object</span> <span class="k">const</span><span class="o">&</span> <span class="n">obj</span><span class="p">)</span>
<span class="o">-></span> <span class="k">decltype</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">serialization</span><span class="o">::</span><span class="n">serialize</span><span class="o"><</span><span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">binary_oarchive</span><span class="o">></span><span class="p">(</span>
<span class="n">std</span><span class="o">::</span><span class="n">declval</span><span class="o"><</span><span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">binary_oarchive</span><span class="o">&></span><span class="p">(),</span> <span class="n">obj</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="kt">void</span><span class="p">())</span> <span class="p">{</span>
<span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">binary_oarchive</span> <span class="n">oa</span><span class="p">(</span><span class="n">o</span><span class="p">);</span>
<span class="n">oa</span> <span class="o"><<</span> <span class="n">obj</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">//--------------------------------------</span>
<span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="nc">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="o">=</span> <span class="k">typename</span> <span class="nc">std</span><span class="o">::</span><span class="n">enable_if</span><span class="o"><</span>
<span class="n">std</span><span class="o">::</span><span class="n">is_assignable</span><span class="o"><</span><span class="n">internal_type</span><span class="p">,</span> <span class="n">Object</span><span class="o">>::</span><span class="n">value</span><span class="o">>::</span><span class="n">type</span><span class="o">></span>
<span class="k">static</span> <span class="k">auto</span> <span class="n">istream</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">istream</span><span class="o">&</span> <span class="n">i</span><span class="p">,</span> <span class="n">Object</span><span class="o">&</span> <span class="n">obj</span><span class="p">)</span>
<span class="o">-></span> <span class="k">decltype</span><span class="p">(</span><span class="n">i</span> <span class="o">>></span> <span class="n">obj</span><span class="p">,</span> <span class="kt">void</span><span class="p">())</span> <span class="p">{</span>
<span class="n">i</span> <span class="o">>></span> <span class="n">obj</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="nc">Object</span><span class="p">,</span> <span class="k">typename</span> <span class="o">=</span> <span class="k">typename</span> <span class="nc">std</span><span class="o">::</span><span class="n">enable_if</span><span class="o"><</span>
<span class="o">!</span><span class="n">std</span><span class="o">::</span><span class="n">is_assignable</span><span class="o"><</span><span class="n">internal_type</span><span class="p">,</span> <span class="n">Object</span><span class="o">>::</span><span class="n">value</span><span class="o">>::</span><span class="n">type</span><span class="o">></span>
<span class="k">static</span> <span class="k">auto</span> <span class="n">istream</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">istream</span><span class="o">&</span> <span class="n">i</span><span class="p">,</span> <span class="n">Object</span><span class="o">&</span> <span class="n">obj</span><span class="p">)</span>
<span class="o">-></span> <span class="k">decltype</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">serialization</span><span class="o">::</span><span class="n">serialize</span><span class="o"><</span><span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">binary_iarchive</span><span class="o">></span><span class="p">(</span>
<span class="n">std</span><span class="o">::</span><span class="n">declval</span><span class="o"><</span><span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">binary_iarchive</span><span class="o">&></span><span class="p">(),</span> <span class="n">obj</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="kt">void</span><span class="p">())</span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">binary_iarchive</span> <span class="n">ia</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
<span class="n">ia</span> <span class="o">>></span> <span class="n">obj</span><span class="p">;</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">archive</span><span class="o">::</span><span class="n">archive_exception</span><span class="p">)</span> <span class="p">{</span>
<span class="n">i</span><span class="p">.</span><span class="n">setstate</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">ios</span><span class="o">::</span><span class="n">failbit</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">//--------------------------------------</span>
<span class="p">};</span>
<span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">string_type</span><span class="p">;</span>
<span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="nc">T</span><span class="o">></span>
<span class="k">struct</span> <span class="nc">translator_between</span><span class="o"><</span><span class="n">string_type</span><span class="p">,</span> <span class="n">T</span><span class="o">></span> <span class="p">{</span>
<span class="k">typedef</span> <span class="n">SerializationTranslator</span><span class="o"><</span><span class="n">string_type</span><span class="p">,</span> <span class="n">T</span><span class="o">></span> <span class="n">type</span><span class="p">;</span>
<span class="p">};</span>
<span class="k">template</span><span class="o"><></span>
<span class="k">struct</span> <span class="nc">translator_between</span><span class="o"><</span><span class="n">string_type</span><span class="p">,</span> <span class="n">string_type</span><span class="o">></span> <span class="p">{</span>
<span class="k">typedef</span> <span class="n">id_translator</span><span class="o"><</span><span class="n">string_type</span><span class="o">></span> <span class="n">type</span><span class="p">;</span>
<span class="p">};</span>
<span class="p">}</span> <span class="c1">// namespace property_tree</span>
<span class="p">}</span> <span class="c1">// namespace boost</span>
<span class="c1">//==============================================================================</span>
<span class="k">template</span> <span class="o"><</span><span class="k">typename</span> <span class="nc">T</span><span class="o">></span>
<span class="kt">void</span> <span class="n">test_ptree</span><span class="p">(</span><span class="n">T</span> <span class="k">const</span><span class="o">&</span> <span class="n">obj</span><span class="p">)</span> <span class="p">{</span>
<span class="n">pt</span><span class="o">::</span><span class="n">ptree</span> <span class="n">tree</span><span class="p">;</span>
<span class="n">tree</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"data"</span><span class="p">,</span> <span class="n">obj</span><span class="p">);</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">tree</span><span class="p">.</span><span class="n">get</span><span class="o"><</span><span class="n">T</span><span class="o">></span><span class="p">(</span><span class="s">"data"</span><span class="p">)</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">//==============================================================================</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">test_ptree</span><span class="p">(</span><span class="mi">42</span><span class="p">);</span>
<span class="n">test_ptree</span><span class="p">(</span><span class="mf">4.7f</span><span class="p">);</span>
<span class="n">test_ptree</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">{</span><span class="s">"Hello world"</span><span class="p">});</span>
<span class="n">test_ptree</span><span class="p">(</span><span class="n">person_t</span><span class="p">{</span><span class="s">"Homer"</span><span class="p">,</span> <span class="s">"Simpson"</span><span class="p">});</span>
<span class="n">entry_t</span> <span class="n">e1</span> <span class="p">{</span><span class="s">"One"</span><span class="p">,</span> <span class="mi">1</span><span class="p">};</span>
<span class="n">entry_t</span> <span class="n">e2</span> <span class="p">{</span><span class="s">"Two"</span><span class="p">,</span> <span class="mi">2</span><span class="p">};</span>
<span class="n">data_t</span> <span class="n">data</span> <span class="p">{</span><span class="s">"Data"</span><span class="p">,</span> <span class="p">{</span><span class="n">e1</span><span class="p">,</span> <span class="n">e2</span><span class="p">}};</span>
<span class="n">pt</span><span class="o">::</span><span class="n">ptree</span> <span class="n">tree</span><span class="p">;</span>
<span class="n">tree</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="s">"data"</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span>
<span class="k">auto</span> <span class="n">ret</span> <span class="o">=</span> <span class="n">tree</span><span class="p">.</span><span class="n">get</span><span class="o"><</span><span class="n">data_t</span><span class="o">></span><span class="p">(</span><span class="s">"data"</span><span class="p">);</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">ret</span><span class="p">.</span><span class="n">name</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span> <span class="o">&</span><span class="nl">e</span> <span class="p">:</span> <span class="n">ret</span><span class="p">.</span><span class="n">entries</span><span class="p">)</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">e</span><span class="p">.</span><span class="n">key</span> <span class="o"><<</span> <span class="s">":"</span> <span class="o"><<</span> <span class="n">e</span><span class="p">.</span><span class="n">value</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p><strong>Output:</strong></p>
<div class="highlight"><pre><span></span><code><span class="mf">42</span>
<span class="mf">4.7</span>
<span class="n">Hello</span> <span class="n">world</span>
<span class="n">Homer</span> <span class="n">Simpson</span>
<span class="kd">Data</span>
<span class="kr">On</span><span class="n">e</span><span class="p">:</span><span class="mf">1</span>
<span class="n">Two</span><span class="p">:</span><span class="mf">2</span>
</code></pre></div>Boost Graph: Components of a directed graph2013-12-11T00:48:00+01:002013-12-11T00:48:00+01:00Michael Munzerttag:None,2013-12-11:/articles/graph_connected_components<p>This article describes a small workaround for a "shortcoming" of Boost Graph. My situation is the following: Given a directed graph, I want to display just the component containing a special node. Technically speaking I'm looking for the connected component containing a special node. Although Boost Graph comes with plenty …</p><p>This article describes a small workaround for a "shortcoming" of Boost Graph. My situation is the following: Given a directed graph, I want to display just the component containing a special node. Technically speaking I'm looking for the connected component containing a special node. Although Boost Graph comes with plenty of algorithms, there is no direct function for this.</p>
<p>For this discussion we will use the following graph: <img alt="Graph" src="/images/graph.png"></p>
<div class="highlight"><pre><span></span><code><span class="mf">0</span> <span class="o">-></span> <span class="mf">1</span>
<span class="mf">0</span> <span class="o">-></span> <span class="mf">2</span>
<span class="mf">1</span> <span class="o">-></span> <span class="mf">2</span>
<span class="mf">4</span> <span class="o">-></span> <span class="mf">3</span>
</code></pre></div>
<p>If the graph was <strong>undirected</strong> we could use <code>boost::connected_components</code> and be happy. But this algorithm is not made for directed graphs and correspondingly gives bad results; we get three components for our graph: </p>
<div class="highlight"><pre><span></span><code><span class="n">Node</span><span class="o">:</span> <span class="mi">0</span> <span class="n">component</span><span class="o">:</span> <span class="mi">0</span>
<span class="n">Node</span><span class="o">:</span> <span class="mi">1</span> <span class="n">component</span><span class="o">:</span> <span class="mi">0</span>
<span class="n">Node</span><span class="o">:</span> <span class="mi">2</span> <span class="n">component</span><span class="o">:</span> <span class="mi">0</span>
<span class="n">Node</span><span class="o">:</span> <span class="mi">3</span> <span class="n">component</span><span class="o">:</span> <span class="mi">1</span>
<span class="n">Node</span><span class="o">:</span> <span class="mi">4</span> <span class="n">component</span><span class="o">:</span> <span class="mi">2</span>
</code></pre></div>
<p>For <strong>directed</strong> graphs there is <code>boost::strong_components</code>. But two vertices <code>A</code> and <code>B</code> are only in one strong component if there is a path from <code>A</code> to <code>B</code> and vice versa. That is not given in the sample graph from above and we get five strong components for this graph. </p>
<p>Ideally we would have an adapter to create a shallow copy of a directed graph which is undirected. Currently I am not aware of such a feature, so we might go with a copy instead. However copying the whole graph will give some performance issues on large graphs, so we just transform the given graph and reverse the transform after the calculation. </p>
<p>We want each component to behave like a strong component. So whenever we have a path from <code>A</code> to <code>B</code> we need to make sure, that the path from <code>B</code> to <code>A</code> is also available. The simplest solution might be to just add all edges with inverted direction:</p>
<div class="highlight"><pre><span></span><code><span class="n">boost</span><span class="o">::</span><span class="n">add_edge</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">target</span><span class="p">(</span><span class="n">edge</span><span class="p">,</span> <span class="n">graph</span><span class="p">),</span> <span class="n">boost</span><span class="o">::</span><span class="n">source</span><span class="p">(</span><span class="n">edge</span><span class="p">,</span> <span class="n">graph</span><span class="p">),</span> <span class="n">graph</span><span class="p">);</span>
</code></pre></div>
<p>A small encapsulation for transform, the calculation and the reversal of the transform may then look like this:</p>
<div class="highlight"><pre><span></span><code><span class="kt">void</span> <span class="nf">strong_components</span><span class="p">(</span><span class="n">graph_t</span> <span class="o">&</span><span class="n">graph</span><span class="p">)</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="n">edge_t</span><span class="o">></span> <span class="n">temp_edges</span><span class="p">;</span>
<span class="k">auto</span> <span class="n">edges</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">edges</span><span class="p">(</span><span class="n">graph</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">edges</span><span class="p">.</span><span class="n">first</span><span class="p">;</span> <span class="n">it</span> <span class="o">!=</span> <span class="n">edges</span><span class="p">.</span><span class="n">second</span><span class="p">;</span> <span class="o">++</span><span class="n">it</span><span class="p">)</span> <span class="p">{</span>
<span class="k">auto</span> <span class="n">pair</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">add_edge</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">target</span><span class="p">(</span><span class="o">*</span><span class="n">it</span><span class="p">,</span> <span class="n">graph</span><span class="p">),</span>
<span class="n">boost</span><span class="o">::</span><span class="n">source</span><span class="p">(</span><span class="o">*</span><span class="n">it</span><span class="p">,</span> <span class="n">graph</span><span class="p">),</span>
<span class="n">graph</span><span class="p">);</span>
<span class="n">temp_edges</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">pair</span><span class="p">.</span><span class="n">first</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">graph</span><span class="p">[</span><span class="n">boost</span><span class="o">::</span><span class="n">graph_bundle</span><span class="p">].</span><span class="n">number_of_components</span> <span class="o">=</span>
<span class="n">boost</span><span class="o">::</span><span class="n">strong_components</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span>
<span class="n">boost</span><span class="o">::</span><span class="n">get</span><span class="p">(</span><span class="o">&</span><span class="n">node_properties</span><span class="o">::</span><span class="n">component</span><span class="p">,</span> <span class="n">graph</span><span class="p">));</span>
<span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="nl">e</span> <span class="p">:</span> <span class="n">temp_edges</span><span class="p">)</span> <span class="p">{</span>
<span class="n">boost</span><span class="o">::</span><span class="n">remove_edge</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">graph</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p><strong>Note:</strong> </p>
<ul>
<li><code>boost::remove_edge</code> might invalidate other edge descriptors. In this example we are using an adjacency list for which this ok (<a href="http://www.boost.org/doc/libs/1_55_0/libs/graph/doc/adjacency_list.html">see Iterator and Descriptor Stability/Invalidation</a>).</li>
<li>Once the graph is transformed the algorithm <code>boost::connected_components</code> <em>should</em> give the same results since every route in a connected component is now available. Furthermore it <em>should</em> be faster, since it doesn't need to check for strong connectivity. However, this is not specified by Boost Graph and depends heavily on the implementation. So be very cautious if you replace <code>boost::strong_components</code> and check the implementation in your case.</li>
</ul>
<h2>Complete example</h2>
<p>Here is the full example to play:</p>
<div class="highlight"><pre><span></span><code><span class="cp">#include</span> <span class="cpf"><boost/graph/adjacency_list.hpp></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><boost/graph/connected_components.hpp></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><boost/graph/strong_components.hpp></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><iostream></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><vector></span><span class="cp"></span>
<span class="c1">//==============================================================================</span>
<span class="k">struct</span> <span class="nc">node_properties</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">component</span><span class="p">;</span>
<span class="p">};</span>
<span class="k">struct</span> <span class="nc">edge_properties</span> <span class="p">{</span>
<span class="p">};</span>
<span class="k">struct</span> <span class="nc">graph_properties</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">number_of_components</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">//--------------------------------------</span>
<span class="k">typedef</span> <span class="n">boost</span><span class="o">::</span><span class="n">adjacency_list</span><span class="o"><</span><span class="n">boost</span><span class="o">::</span><span class="n">vecS</span><span class="p">,</span> <span class="n">boost</span><span class="o">::</span><span class="n">vecS</span><span class="p">,</span> <span class="n">boost</span><span class="o">::</span><span class="n">directedS</span><span class="p">,</span>
<span class="n">node_properties</span><span class="p">,</span> <span class="n">edge_properties</span><span class="p">,</span> <span class="n">graph_properties</span><span class="o">></span> <span class="n">graph_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="nc">boost</span><span class="o">::</span><span class="n">graph_traits</span><span class="o"><</span><span class="n">graph_t</span><span class="o">>::</span><span class="n">vertex_descriptor</span> <span class="n">vertex_t</span><span class="p">;</span>
<span class="k">typedef</span> <span class="k">typename</span> <span class="nc">boost</span><span class="o">::</span><span class="n">graph_traits</span><span class="o"><</span><span class="n">graph_t</span><span class="o">>::</span><span class="n">edge_descriptor</span> <span class="n">edge_t</span><span class="p">;</span>
<span class="c1">//==============================================================================</span>
<span class="kt">void</span> <span class="nf">print_graph</span><span class="p">(</span><span class="k">const</span> <span class="n">graph_t</span> <span class="o">&</span><span class="n">graph</span><span class="p">)</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Graph:"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="k">auto</span> <span class="n">edges</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">edges</span><span class="p">(</span><span class="n">graph</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">edges</span><span class="p">.</span><span class="n">first</span><span class="p">;</span> <span class="n">it</span> <span class="o">!=</span> <span class="n">edges</span><span class="p">.</span><span class="n">second</span><span class="p">;</span> <span class="o">++</span><span class="n">it</span><span class="p">)</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="n">boost</span><span class="o">::</span><span class="n">source</span><span class="p">(</span><span class="o">*</span><span class="n">it</span><span class="p">,</span> <span class="n">graph</span><span class="p">)</span> <span class="o"><<</span> <span class="s">" -> "</span>
<span class="o"><<</span> <span class="n">boost</span><span class="o">::</span><span class="n">target</span><span class="p">(</span><span class="o">*</span><span class="n">it</span><span class="p">,</span> <span class="n">graph</span><span class="p">)</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">//==============================================================================</span>
<span class="kt">void</span> <span class="nf">print_components</span><span class="p">(</span><span class="k">const</span> <span class="n">graph_t</span> <span class="o">&</span><span class="n">graph</span><span class="p">)</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"</span><span class="se">\n</span><span class="s">Components: "</span>
<span class="o"><<</span> <span class="n">graph</span><span class="p">[</span><span class="n">boost</span><span class="o">::</span><span class="n">graph_bundle</span><span class="p">].</span><span class="n">number_of_components</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="k">auto</span> <span class="n">nodes</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">vertices</span><span class="p">(</span><span class="n">graph</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">nodes</span><span class="p">.</span><span class="n">first</span><span class="p">;</span> <span class="n">it</span> <span class="o">!=</span> <span class="n">nodes</span><span class="p">.</span><span class="n">second</span><span class="p">;</span> <span class="o">++</span><span class="n">it</span><span class="p">)</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Node: "</span> <span class="o"><<</span> <span class="o">*</span><span class="n">it</span> <span class="o"><<</span> <span class="s">" component: "</span> <span class="o"><<</span> <span class="n">graph</span><span class="p">[</span><span class="o">*</span><span class="n">it</span><span class="p">].</span><span class="n">component</span>
<span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">//==============================================================================</span>
<span class="kt">void</span> <span class="nf">strong_components</span><span class="p">(</span><span class="n">graph_t</span> <span class="o">&</span><span class="n">graph</span><span class="p">)</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="n">edge_t</span><span class="o">></span> <span class="n">temp_edges</span><span class="p">;</span>
<span class="k">auto</span> <span class="n">edges</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">edges</span><span class="p">(</span><span class="n">graph</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="k">auto</span> <span class="n">it</span> <span class="o">=</span> <span class="n">edges</span><span class="p">.</span><span class="n">first</span><span class="p">;</span> <span class="n">it</span> <span class="o">!=</span> <span class="n">edges</span><span class="p">.</span><span class="n">second</span><span class="p">;</span> <span class="o">++</span><span class="n">it</span><span class="p">)</span> <span class="p">{</span>
<span class="k">auto</span> <span class="n">pair</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">add_edge</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">target</span><span class="p">(</span><span class="o">*</span><span class="n">it</span><span class="p">,</span> <span class="n">graph</span><span class="p">),</span>
<span class="n">boost</span><span class="o">::</span><span class="n">source</span><span class="p">(</span><span class="o">*</span><span class="n">it</span><span class="p">,</span> <span class="n">graph</span><span class="p">),</span>
<span class="n">graph</span><span class="p">);</span>
<span class="n">temp_edges</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">pair</span><span class="p">.</span><span class="n">first</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">graph</span><span class="p">[</span><span class="n">boost</span><span class="o">::</span><span class="n">graph_bundle</span><span class="p">].</span><span class="n">number_of_components</span> <span class="o">=</span>
<span class="n">boost</span><span class="o">::</span><span class="n">strong_components</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span>
<span class="n">boost</span><span class="o">::</span><span class="n">get</span><span class="p">(</span><span class="o">&</span><span class="n">node_properties</span><span class="o">::</span><span class="n">component</span><span class="p">,</span> <span class="n">graph</span><span class="p">));</span>
<span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span> <span class="o">&</span> <span class="nl">e</span> <span class="p">:</span> <span class="n">temp_edges</span><span class="p">)</span> <span class="p">{</span>
<span class="n">boost</span><span class="o">::</span><span class="n">remove_edge</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">graph</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">//==============================================================================</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">graph_t</span> <span class="n">graph</span><span class="p">;</span>
<span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="n">vertex_t</span><span class="o">></span> <span class="n">vertices</span><span class="p">;</span>
<span class="n">vertices</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">add_vertex</span><span class="p">(</span><span class="n">graph</span><span class="p">));</span>
<span class="n">vertices</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">add_vertex</span><span class="p">(</span><span class="n">graph</span><span class="p">));</span>
<span class="n">vertices</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">add_vertex</span><span class="p">(</span><span class="n">graph</span><span class="p">));</span>
<span class="n">vertices</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">add_vertex</span><span class="p">(</span><span class="n">graph</span><span class="p">));</span>
<span class="n">vertices</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">boost</span><span class="o">::</span><span class="n">add_vertex</span><span class="p">(</span><span class="n">graph</span><span class="p">));</span>
<span class="n">boost</span><span class="o">::</span><span class="n">add_edge</span><span class="p">(</span><span class="n">vertices</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="n">vertices</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="n">graph</span><span class="p">);</span>
<span class="n">boost</span><span class="o">::</span><span class="n">add_edge</span><span class="p">(</span><span class="n">vertices</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span> <span class="n">vertices</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="n">graph</span><span class="p">);</span>
<span class="n">boost</span><span class="o">::</span><span class="n">add_edge</span><span class="p">(</span><span class="n">vertices</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="mi">1</span><span class="p">),</span> <span class="n">vertices</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="n">graph</span><span class="p">);</span>
<span class="n">boost</span><span class="o">::</span><span class="n">add_edge</span><span class="p">(</span><span class="n">vertices</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="mi">4</span><span class="p">),</span> <span class="n">vertices</span><span class="p">.</span><span class="n">at</span><span class="p">(</span><span class="mi">3</span><span class="p">),</span> <span class="n">graph</span><span class="p">);</span>
<span class="n">graph</span><span class="p">[</span><span class="n">boost</span><span class="o">::</span><span class="n">graph_bundle</span><span class="p">].</span><span class="n">number_of_components</span> <span class="o">=</span>
<span class="n">boost</span><span class="o">::</span><span class="n">connected_components</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span>
<span class="n">boost</span><span class="o">::</span><span class="n">get</span><span class="p">(</span><span class="o">&</span><span class="n">node_properties</span><span class="o">::</span><span class="n">component</span><span class="p">,</span> <span class="n">graph</span><span class="p">));</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Without adaption:</span><span class="se">\n</span><span class="s">-----------------"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="n">print_graph</span><span class="p">(</span><span class="n">graph</span><span class="p">);</span>
<span class="n">print_components</span><span class="p">(</span><span class="n">graph</span><span class="p">);</span>
<span class="n">strong_components</span><span class="p">(</span><span class="n">graph</span><span class="p">);</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"</span><span class="se">\n</span><span class="s">With additional edges:</span><span class="se">\n</span><span class="s">----------------------"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="n">print_graph</span><span class="p">(</span><span class="n">graph</span><span class="p">);</span>
<span class="n">print_components</span><span class="p">(</span><span class="n">graph</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p><strong>Output:</strong></p>
<div class="highlight"><pre><span></span><code><span class="gh">Without adaption:</span>
<span class="gh">-----------------</span>
Graph:
0 -> 1
0 -> 2
1 -> 2
4 -> 3
Components: 3
Node: 0 component: 0
Node: 1 component: 0
Node: 2 component: 0
Node: 3 component: 1
Node: 4 component: 2
<span class="gh">With additional edges:</span>
<span class="gh">----------------------</span>
Graph:
0 -> 1
0 -> 2
1 -> 2
4 -> 3
Components: 2
Node: 0 component: 0
Node: 1 component: 0
Node: 2 component: 0
Node: 3 component: 1
Node: 4 component: 1
</code></pre></div>
<p><strong>Note:</strong> You might get maybe unintialized warnings when using gcc to compile this. Those are not a problem of the example but <a href="https://svn.boost.org/trac/boost/ticket/5706">well known</a>.</p>Boost Spirit Qi: Position tracking during parsing2013-12-10T16:41:00+01:002013-12-10T16:41:00+01:00Michael Munzerttag:None,2013-12-10:/articles/position_tracking<p>Usually we use a tool like Boost Spirit Qi to retrieve information from a source file. However, in some situations (like building a syntax highlighter) that is not enough and we also need some meta data about the information. This short article will describe a convenient way to get additionally …</p><p>Usually we use a tool like Boost Spirit Qi to retrieve information from a source file. However, in some situations (like building a syntax highlighter) that is not enough and we also need some meta data about the information. This short article will describe a convenient way to get additionally the position of respective data points. </p>
<p>Boost Spirit Qi offers the <code>qi::iter_pos</code> parser which provides access to the underlying iterator. The iterator itself doesn't provide the position directly but we can calculate it. To do this, we need to know the respective starting point of the input. </p>
<p>We could store the starting point next to the parser but that would increase the effort of using this parser, since we need to set it each time before parsing. The better solution is to embed this data into a parser component, so the reference point can be set by the parser. We provide a small encapsulation:</p>
<div class="highlight"><pre><span></span><code><span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="nc">Iterator</span><span class="o">></span>
<span class="k">struct</span> <span class="nc">CurrentPos</span> <span class="p">{</span>
<span class="n">CurrentPos</span><span class="p">()</span> <span class="p">{</span>
<span class="n">save_start_pos</span> <span class="o">=</span> <span class="n">qi</span><span class="o">::</span><span class="n">omit</span><span class="p">[</span><span class="n">boost</span><span class="o">::</span><span class="n">spirit</span><span class="o">::</span><span class="n">repository</span><span class="o">::</span><span class="n">qi</span><span class="o">::</span><span class="n">iter_pos</span><span class="p">[</span>
<span class="n">phx</span><span class="o">::</span><span class="n">bind</span><span class="p">(</span><span class="o">&</span><span class="n">CurrentPos</span><span class="o">::</span><span class="n">setStartPos</span><span class="p">,</span> <span class="k">this</span><span class="p">,</span> <span class="n">qi</span><span class="o">::</span><span class="n">_1</span><span class="p">)]];</span>
<span class="n">current_pos</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">spirit</span><span class="o">::</span><span class="n">repository</span><span class="o">::</span><span class="n">qi</span><span class="o">::</span><span class="n">iter_pos</span><span class="p">[</span>
<span class="n">qi</span><span class="o">::</span><span class="n">_val</span> <span class="o">=</span> <span class="n">phx</span><span class="o">::</span><span class="n">bind</span><span class="p">(</span><span class="o">&</span><span class="n">CurrentPos</span><span class="o">::</span><span class="n">getCurrentPos</span><span class="p">,</span> <span class="k">this</span><span class="p">,</span> <span class="n">qi</span><span class="o">::</span><span class="n">_1</span><span class="p">)];</span>
<span class="p">}</span>
<span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">Iterator</span><span class="o">></span> <span class="n">save_start_pos</span><span class="p">;</span>
<span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">Iterator</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="p">()</span><span class="o">></span> <span class="n">current_pos</span><span class="p">;</span>
<span class="k">private</span><span class="o">:</span>
<span class="kt">void</span> <span class="n">setStartPos</span><span class="p">(</span><span class="k">const</span> <span class="n">Iterator</span> <span class="o">&</span><span class="n">iterator</span><span class="p">)</span> <span class="p">{</span>
<span class="n">start_pos_</span> <span class="o">=</span> <span class="n">iterator</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">getCurrentPos</span><span class="p">(</span><span class="k">const</span> <span class="n">Iterator</span> <span class="o">&</span><span class="n">iterator</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">distance</span><span class="p">(</span><span class="n">start_pos_</span><span class="p">,</span> <span class="n">iterator</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">Iterator</span> <span class="n">start_pos_</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div>
<p>This component provides two parsing rules:</p>
<ul>
<li><code>save_start_pos</code>: Needs to be called at the beginning of the parsing to store the reference position. It does not provide any attributes.</li>
<li><code>current_pos</code>: Will be called each time we want to get the current position of the parser, which it provides by a ''std::size_t'' attribute.</li>
</ul>
<p>This method works well for source code. However, as soon as you need to process Unicode files and expect additional symbols the position will be wrong. Some Unicode symbols take more then one character in UTF-8 encoding and the underlying iterator doesn't know about that so <code>std::distance</code> doesn't give the desired result. <a href="/articles/parse_unicode">This article</a> describes how to fix that. </p>
<h2>Usage</h2>
<p>To demonstrate this component in action, we want to parse words, which we parse as connected chars for simplicity, and store the position next to them. The data type is just a tuple in our case:</p>
<div class="highlight"><pre><span></span><code><span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">></span> <span class="n">word_t</span><span class="p">;</span>
</code></pre></div>
<p>This leads to the following two rules:</p>
<div class="highlight"><pre><span></span><code><span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">iterator_type</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">(),</span> <span class="n">qi</span><span class="o">::</span><span class="n">space_type</span><span class="o">></span> <span class="n">string</span> <span class="o">=</span>
<span class="n">qi</span><span class="o">::</span><span class="n">lexeme</span><span class="p">[</span><span class="o">+</span><span class="p">(</span><span class="n">qi</span><span class="o">::</span><span class="n">char_</span> <span class="o">-</span> <span class="n">qi</span><span class="o">::</span><span class="n">space</span><span class="p">)];</span>
<span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">iterator_type</span><span class="p">,</span> <span class="n">word_t</span><span class="p">(),</span> <span class="n">qi</span><span class="o">::</span><span class="n">space_type</span><span class="o">></span> <span class="n">word</span> <span class="o">=</span>
<span class="n">current_pos</span><span class="p">.</span><span class="n">current_pos</span> <span class="o">>></span> <span class="n">string</span><span class="p">;</span>
</code></pre></div>
<p>Of course it is essential to call <code>save_start_pos</code> at the beginning of the parsing. So, we just add it to the <code>start</code> rule: </p>
<div class="highlight"><pre><span></span><code><span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">iterator_type</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="n">word_t</span><span class="o">></span><span class="p">(),</span> <span class="n">qi</span><span class="o">::</span><span class="n">space_type</span><span class="o">></span> <span class="n">start</span> <span class="o">=</span>
<span class="n">current_pos</span><span class="p">.</span><span class="n">save_start_pos</span> <span class="o">>></span> <span class="o">*</span><span class="p">(</span><span class="n">word</span><span class="p">);</span>
</code></pre></div>
<h2>Complete example</h2>
<p>Here is the full example to play:</p>
<div class="highlight"><pre><span></span><code><span class="cp">#define BOOST_SPIRIT_USE_PHOENIX_V3</span>
<span class="cp">#define BOOST_SPIRIT_UNICODE</span>
<span class="cp">#include</span> <span class="cpf"><boost/fusion/adapted/std_tuple.hpp></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><boost/spirit/include/phoenix.hpp></span><span class="cp"></span>
<span class="k">namespace</span> <span class="n">phx</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">phoenix</span><span class="p">;</span>
<span class="cp">#include</span> <span class="cpf"><boost/spirit/include/qi.hpp></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><boost/spirit/repository/include/qi_iter_pos.hpp></span><span class="cp"></span>
<span class="k">namespace</span> <span class="n">qi</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">spirit</span><span class="o">::</span><span class="n">qi</span><span class="p">;</span>
<span class="cp">#include</span> <span class="cpf"><iostream></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><string></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><tuple></span><span class="cp"></span>
<span class="c1">//======================================================================</span>
<span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="nc">Iterator</span><span class="o">></span>
<span class="k">struct</span> <span class="nc">CurrentPos</span> <span class="p">{</span>
<span class="n">CurrentPos</span><span class="p">()</span> <span class="p">{</span>
<span class="n">save_start_pos</span> <span class="o">=</span> <span class="n">qi</span><span class="o">::</span><span class="n">omit</span><span class="p">[</span><span class="n">boost</span><span class="o">::</span><span class="n">spirit</span><span class="o">::</span><span class="n">repository</span><span class="o">::</span><span class="n">qi</span><span class="o">::</span><span class="n">iter_pos</span><span class="p">[</span>
<span class="n">phx</span><span class="o">::</span><span class="n">bind</span><span class="p">(</span><span class="o">&</span><span class="n">CurrentPos</span><span class="o">::</span><span class="n">setStartPos</span><span class="p">,</span> <span class="k">this</span><span class="p">,</span> <span class="n">qi</span><span class="o">::</span><span class="n">_1</span><span class="p">)]];</span>
<span class="n">current_pos</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">spirit</span><span class="o">::</span><span class="n">repository</span><span class="o">::</span><span class="n">qi</span><span class="o">::</span><span class="n">iter_pos</span><span class="p">[</span>
<span class="n">qi</span><span class="o">::</span><span class="n">_val</span> <span class="o">=</span> <span class="n">phx</span><span class="o">::</span><span class="n">bind</span><span class="p">(</span><span class="o">&</span><span class="n">CurrentPos</span><span class="o">::</span><span class="n">getCurrentPos</span><span class="p">,</span> <span class="k">this</span><span class="p">,</span> <span class="n">qi</span><span class="o">::</span><span class="n">_1</span><span class="p">)];</span>
<span class="p">}</span>
<span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">Iterator</span><span class="o">></span> <span class="n">save_start_pos</span><span class="p">;</span>
<span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">Iterator</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="p">()</span><span class="o">></span> <span class="n">current_pos</span><span class="p">;</span>
<span class="k">private</span><span class="o">:</span>
<span class="kt">void</span> <span class="n">setStartPos</span><span class="p">(</span><span class="k">const</span> <span class="n">Iterator</span> <span class="o">&</span><span class="n">iterator</span><span class="p">)</span> <span class="p">{</span>
<span class="n">start_pos_</span> <span class="o">=</span> <span class="n">iterator</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">getCurrentPos</span><span class="p">(</span><span class="k">const</span> <span class="n">Iterator</span> <span class="o">&</span><span class="n">iterator</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">distance</span><span class="p">(</span><span class="n">start_pos_</span><span class="p">,</span> <span class="n">iterator</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">Iterator</span> <span class="n">start_pos_</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">//======================================================================</span>
<span class="kt">int</span> <span class="nf">main</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">input</span><span class="p">(</span><span class="s">"Hello world!"</span><span class="p">);</span>
<span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">::</span><span class="n">const_iterator</span> <span class="n">iterator_type</span><span class="p">;</span>
<span class="n">iterator_type</span> <span class="n">first</span><span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">begin</span><span class="p">()),</span> <span class="n">last</span><span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">end</span><span class="p">());</span>
<span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">></span> <span class="n">word_t</span><span class="p">;</span>
<span class="n">CurrentPos</span><span class="o"><</span><span class="n">iterator_type</span><span class="o">></span> <span class="n">current_pos</span><span class="p">;</span>
<span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">iterator_type</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">(),</span> <span class="n">qi</span><span class="o">::</span><span class="n">space_type</span><span class="o">></span> <span class="n">string</span> <span class="o">=</span>
<span class="n">qi</span><span class="o">::</span><span class="n">lexeme</span><span class="p">[</span><span class="o">+</span><span class="p">(</span><span class="n">qi</span><span class="o">::</span><span class="n">char_</span> <span class="o">-</span> <span class="n">qi</span><span class="o">::</span><span class="n">space</span><span class="p">)];</span>
<span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">iterator_type</span><span class="p">,</span> <span class="n">word_t</span><span class="p">(),</span> <span class="n">qi</span><span class="o">::</span><span class="n">space_type</span><span class="o">></span> <span class="n">word</span> <span class="o">=</span>
<span class="n">current_pos</span><span class="p">.</span><span class="n">current_pos</span> <span class="o">>></span> <span class="n">string</span><span class="p">;</span>
<span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">iterator_type</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="n">word_t</span><span class="o">></span><span class="p">(),</span> <span class="n">qi</span><span class="o">::</span><span class="n">space_type</span><span class="o">></span> <span class="n">start</span> <span class="o">=</span>
<span class="n">current_pos</span><span class="p">.</span><span class="n">save_start_pos</span> <span class="o">>></span> <span class="o">*</span><span class="p">(</span><span class="n">word</span><span class="p">);</span>
<span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o"><</span><span class="n">word_t</span><span class="o">></span> <span class="n">data</span><span class="p">;</span>
<span class="kt">bool</span> <span class="n">result</span> <span class="o">=</span> <span class="n">qi</span><span class="o">::</span><span class="n">phrase_parse</span><span class="p">(</span><span class="n">first</span><span class="p">,</span> <span class="n">last</span><span class="p">,</span> <span class="n">start</span><span class="p">,</span> <span class="n">qi</span><span class="o">::</span><span class="n">space</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">result</span><span class="p">)</span> <span class="p">{</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">first</span> <span class="o">==</span> <span class="n">last</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">result</span><span class="p">)</span> <span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="k">const</span> <span class="k">auto</span> <span class="o">&</span><span class="nl">e</span> <span class="p">:</span> <span class="n">data</span><span class="p">)</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Position: "</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">get</span><span class="o"><</span><span class="mi">0</span><span class="o">></span><span class="p">(</span><span class="n">e</span><span class="p">)</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span>
<span class="o"><<</span> <span class="s">"Word: "</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">get</span><span class="o"><</span><span class="mi">1</span><span class="o">></span><span class="p">(</span><span class="n">e</span><span class="p">)</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Failure"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p><strong>Output:</strong></p>
<div class="highlight"><pre><span></span><code><span class="nl">Position</span><span class="p">:</span> <span class="mi">0</span>
<span class="nl">Word</span><span class="p">:</span> <span class="n">Hello</span>
<span class="nl">Position</span><span class="p">:</span> <span class="mi">6</span>
<span class="nl">Word</span><span class="p">:</span> <span class="n">world</span><span class="o">!</span>
</code></pre></div>Boost Spirit Qi: Position tracking for Unicode strings2013-12-05T23:16:00+01:002013-12-05T23:16:00+01:00Michael Munzerttag:None,2013-12-05:/articles/parse_unicode<p>In <a href="/articles/position_tracking">this article</a> I described how to retrieve data points and their positions during parsing. However, this method has a little flaw, it doesn't work correctly with Unicode input. We're going to fix this problem now. </p>
<p>Since we rely on the underlying iterator, the position depends on the used iterator …</p><p>In <a href="/articles/position_tracking">this article</a> I described how to retrieve data points and their positions during parsing. However, this method has a little flaw, it doesn't work correctly with Unicode input. We're going to fix this problem now. </p>
<p>Since we rely on the underlying iterator, the position depends on the used iterator type. Commonly the <code>std::string::const_iterator</code> is used and that does not play well with Unicode input, since in UTF-8 encoding some (or actually many) symbols take more then one character of the stream. </p>
<p>For solving this problem we need an Unicode aware iterator, which we get by wrapping our iterator in a <code>boost::u8_to_u32_iterator</code>.</p>
<div class="highlight"><pre><span></span><code><span class="k">typedef</span> <span class="n">boost</span><span class="o">::</span><span class="n">u8_to_u32_iterator</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">::</span><span class="n">const_iterator</span><span class="o">></span> <span class="n">iterator_type</span><span class="p">;</span>
</code></pre></div>
<p>There is some more work to do. String attributes now reflect Unicode symbols in the UTF-32 encoding which doesn't match with <code>std::string</code>. So, we need to catch the attribute as <code>std::u32string</code> and convert this back to <code>std::string</code> again using boost iterators:</p>
<div class="highlight"><pre><span></span><code><span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">to_utf8</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">u32string</span><span class="o">&</span> <span class="n">input</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">(</span>
<span class="n">boost</span><span class="o">::</span><span class="n">u32_to_u8_iterator</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">u32string</span><span class="o">::</span><span class="n">const_iterator</span><span class="o">></span><span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">begin</span><span class="p">()),</span>
<span class="n">boost</span><span class="o">::</span><span class="n">u32_to_u8_iterator</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">u32string</span><span class="o">::</span><span class="n">const_iterator</span><span class="o">></span><span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">end</span><span class="p">()));</span>
<span class="p">}</span>
<span class="n">BOOST_PHOENIX_ADAPT_FUNCTION</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">,</span> <span class="n">to_utf8_</span><span class="p">,</span> <span class="n">to_utf8</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</code></pre></div>
<p>The macro in the last line allows to call the function in a semantic action directly, otherwise we would need <code>boost::phoenix::bind</code> for this. As said we have to wrap the output in a <code>std::u32string</code> first, so parser rules may look like this:</p>
<div class="highlight"><pre><span></span><code> <span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">iterator_type</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">u32string</span><span class="p">()</span><span class="o">></span> <span class="n">string_u32</span> <span class="o">=</span>
<span class="o">*</span><span class="p">(</span><span class="n">qi</span><span class="o">::</span><span class="n">standard_wide</span><span class="o">::</span><span class="n">char_</span> <span class="o">-</span> <span class="n">qi</span><span class="o">::</span><span class="n">eoi</span><span class="p">);</span>
<span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">iterator_type</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">()</span><span class="o">></span> <span class="n">string</span> <span class="o">=</span>
<span class="n">string_u32</span> <span class="p">[</span><span class="n">qi</span><span class="o">::</span><span class="n">_val</span> <span class="o">=</span> <span class="n">to_utf8_</span><span class="p">(</span><span class="n">qi</span><span class="o">::</span><span class="n">_1</span><span class="p">)];</span>
</code></pre></div>
<p>We could also wrap these two rules in one larger rule:</p>
<div class="highlight"><pre><span></span><code> <span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">iterator_type</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">()</span><span class="o">></span> <span class="n">string</span> <span class="o">=</span>
<span class="n">boost</span><span class="o">::</span><span class="n">spirit</span><span class="o">::</span><span class="n">attr_cast</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">u32string</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">u32string</span><span class="o">></span><span class="p">(</span>
<span class="o">*</span><span class="p">(</span><span class="n">qi</span><span class="o">::</span><span class="n">standard_wide</span><span class="o">::</span><span class="n">char_</span> <span class="o">-</span> <span class="n">qi</span><span class="o">::</span><span class="n">eoi</span><span class="p">))</span> <span class="p">[</span><span class="n">qi</span><span class="o">::</span><span class="n">_val</span> <span class="o">=</span> <span class="n">to_utf8_</span><span class="p">(</span><span class="n">qi</span><span class="o">::</span><span class="n">_1</span><span class="p">)];</span>
</code></pre></div>
<h2>Complete example</h2>
<p>Well, enough said, here is the full example to play:</p>
<div class="highlight"><pre><span></span><code><span class="cp">#define BOOST_SPIRIT_USE_PHOENIX_V3</span>
<span class="cp">#define BOOST_SPIRIT_UNICODE</span>
<span class="cp">#include</span> <span class="cpf"><boost/regex/pending/unicode_iterator.hpp></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><boost/fusion/adapted/std_tuple.hpp></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><boost/phoenix/function/adapt_function.hpp></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><boost/spirit/include/phoenix.hpp></span><span class="cp"></span>
<span class="k">namespace</span> <span class="n">phx</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">phoenix</span><span class="p">;</span>
<span class="cp">#include</span> <span class="cpf"><boost/spirit/include/qi.hpp></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><boost/spirit/repository/include/qi_iter_pos.hpp></span><span class="cp"></span>
<span class="k">namespace</span> <span class="n">qi</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">spirit</span><span class="o">::</span><span class="n">qi</span><span class="p">;</span>
<span class="cp">#include</span> <span class="cpf"><iostream></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><string></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><tuple></span><span class="cp"></span>
<span class="c1">//==============================================================================</span>
<span class="k">template</span><span class="o"><</span><span class="k">typename</span> <span class="nc">Iterator</span><span class="o">></span>
<span class="k">struct</span> <span class="nc">CurrentPos</span> <span class="p">{</span>
<span class="n">CurrentPos</span><span class="p">()</span> <span class="p">{</span>
<span class="n">save_start_pos</span> <span class="o">=</span> <span class="n">qi</span><span class="o">::</span><span class="n">omit</span><span class="p">[</span><span class="n">boost</span><span class="o">::</span><span class="n">spirit</span><span class="o">::</span><span class="n">repository</span><span class="o">::</span><span class="n">qi</span><span class="o">::</span><span class="n">iter_pos</span><span class="p">[</span>
<span class="n">phx</span><span class="o">::</span><span class="n">bind</span><span class="p">(</span><span class="o">&</span><span class="n">CurrentPos</span><span class="o">::</span><span class="n">setStartPos</span><span class="p">,</span> <span class="k">this</span><span class="p">,</span> <span class="n">qi</span><span class="o">::</span><span class="n">_1</span><span class="p">)]];</span>
<span class="n">current_pos</span> <span class="o">=</span> <span class="n">boost</span><span class="o">::</span><span class="n">spirit</span><span class="o">::</span><span class="n">repository</span><span class="o">::</span><span class="n">qi</span><span class="o">::</span><span class="n">iter_pos</span><span class="p">[</span>
<span class="n">qi</span><span class="o">::</span><span class="n">_val</span> <span class="o">=</span> <span class="n">phx</span><span class="o">::</span><span class="n">bind</span><span class="p">(</span><span class="o">&</span><span class="n">CurrentPos</span><span class="o">::</span><span class="n">getCurrentPos</span><span class="p">,</span> <span class="k">this</span><span class="p">,</span> <span class="n">qi</span><span class="o">::</span><span class="n">_1</span><span class="p">)];</span>
<span class="p">}</span>
<span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">Iterator</span><span class="o">></span> <span class="n">save_start_pos</span><span class="p">;</span>
<span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">Iterator</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="p">()</span><span class="o">></span> <span class="n">current_pos</span><span class="p">;</span>
<span class="k">private</span><span class="o">:</span>
<span class="kt">void</span> <span class="n">setStartPos</span><span class="p">(</span><span class="k">const</span> <span class="n">Iterator</span> <span class="o">&</span><span class="n">iterator</span><span class="p">)</span> <span class="p">{</span>
<span class="n">start_pos_</span> <span class="o">=</span> <span class="n">iterator</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">std</span><span class="o">::</span><span class="kt">size_t</span> <span class="n">getCurrentPos</span><span class="p">(</span><span class="k">const</span> <span class="n">Iterator</span> <span class="o">&</span><span class="n">iterator</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">distance</span><span class="p">(</span><span class="n">start_pos_</span><span class="p">,</span> <span class="n">iterator</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">Iterator</span> <span class="n">start_pos_</span><span class="p">;</span>
<span class="p">};</span>
<span class="c1">//==============================================================================</span>
<span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">to_utf8</span><span class="p">(</span><span class="k">const</span> <span class="n">std</span><span class="o">::</span><span class="n">u32string</span><span class="o">&</span> <span class="n">input</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">(</span>
<span class="n">boost</span><span class="o">::</span><span class="n">u32_to_u8_iterator</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">u32string</span><span class="o">::</span><span class="n">const_iterator</span><span class="o">></span><span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">begin</span><span class="p">()),</span>
<span class="n">boost</span><span class="o">::</span><span class="n">u32_to_u8_iterator</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">u32string</span><span class="o">::</span><span class="n">const_iterator</span><span class="o">></span><span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">end</span><span class="p">()));</span>
<span class="p">}</span>
<span class="n">BOOST_PHOENIX_ADAPT_FUNCTION</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">,</span> <span class="n">to_utf8_</span><span class="p">,</span> <span class="n">to_utf8</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="c1">//==============================================================================</span>
<span class="kt">int</span> <span class="n">main</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">input</span><span class="p">(</span><span class="sa">u8</span><span class="s">"Hello Unicode world! ♠♣♥♦ äöüß"</span><span class="p">);</span>
<span class="k">typedef</span> <span class="n">boost</span><span class="o">::</span><span class="n">u8_to_u32_iterator</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">::</span><span class="n">const_iterator</span><span class="o">></span> <span class="n">iterator_type</span><span class="p">;</span>
<span class="n">iterator_type</span> <span class="nf">first</span><span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">begin</span><span class="p">()),</span>
<span class="n">last</span><span class="p">(</span><span class="n">input</span><span class="p">.</span><span class="n">end</span><span class="p">());</span>
<span class="k">typedef</span> <span class="n">std</span><span class="o">::</span><span class="n">tuple</span><span class="o"><</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="kt">size_t</span><span class="o">></span> <span class="n">ast_t</span><span class="p">;</span>
<span class="n">CurrentPos</span><span class="o"><</span><span class="n">iterator_type</span><span class="o">></span> <span class="n">current_pos</span><span class="p">;</span>
<span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">iterator_type</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">u32string</span><span class="p">()</span><span class="o">></span> <span class="n">string_u32</span> <span class="o">=</span>
<span class="o">*</span><span class="p">(</span><span class="n">qi</span><span class="o">::</span><span class="n">standard_wide</span><span class="o">::</span><span class="n">char_</span> <span class="o">-</span> <span class="n">qi</span><span class="o">::</span><span class="n">eoi</span><span class="p">);</span>
<span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">iterator_type</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="p">()</span><span class="o">></span> <span class="n">string</span> <span class="o">=</span>
<span class="n">string_u32</span> <span class="p">[</span><span class="n">qi</span><span class="o">::</span><span class="n">_val</span> <span class="o">=</span> <span class="n">to_utf8_</span><span class="p">(</span><span class="n">qi</span><span class="o">::</span><span class="n">_1</span><span class="p">)];</span>
<span class="n">qi</span><span class="o">::</span><span class="n">rule</span><span class="o"><</span><span class="n">iterator_type</span><span class="p">,</span> <span class="n">ast_t</span><span class="p">()</span><span class="o">></span> <span class="n">rule</span> <span class="o">=</span>
<span class="n">current_pos</span><span class="p">.</span><span class="n">save_start_pos</span> <span class="o">>></span> <span class="n">string</span> <span class="o">>></span> <span class="n">current_pos</span><span class="p">.</span><span class="n">current_pos</span><span class="p">;</span>
<span class="n">ast_t</span> <span class="n">data</span><span class="p">;</span>
<span class="kt">bool</span> <span class="n">result</span> <span class="o">=</span> <span class="n">qi</span><span class="o">::</span><span class="n">parse</span><span class="p">(</span><span class="n">first</span><span class="p">,</span> <span class="n">last</span><span class="p">,</span> <span class="n">rule</span><span class="p">,</span> <span class="n">data</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">result</span><span class="p">)</span> <span class="p">{</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">first</span> <span class="o">==</span> <span class="n">last</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">result</span><span class="p">)</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Parsed: "</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">get</span><span class="o"><</span><span class="mi">0</span><span class="o">></span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span>
<span class="o"><<</span> <span class="s">"Length: "</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">get</span><span class="o"><</span><span class="mi">1</span><span class="o">></span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o"><<</span> <span class="s">"Failure"</span> <span class="o"><<</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p><strong>Output:</strong></p>
<div class="highlight"><pre><span></span><code><span class="n">Parsed</span><span class="o">:</span> <span class="n">Hello</span> <span class="n">Unicode</span> <span class="n">world</span><span class="o">!</span> <span class="err">♠♣♥♦</span> <span class="err">äöüß</span>
<span class="n">Length</span><span class="o">:</span> <span class="mi">30</span>
</code></pre></div>
<p>Without using the Unicode adaption we would get length 42, since äöüß each take two characters and ♠♣♥♦ each take three.</p>