IT戦記

プログラミング、起業などについて書いているプログラマーのブログです😚

boost::serialization の Dataflow Iterators で base64 生成

はじめに

base64 を作りたいと思って調べたら boost::serialization の Dataflow Iterators が便利そう。
Serialization - Dataflow Iterators

実際に書いてみた

#include <iostream>
#include <boost/pfto.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/transform_width.hpp>

int main()
{
    using namespace std;
    using namespace boost::archive::iterators;

    typedef base64_from_binary<transform_width<istream_iterator<char>, 6, 8 > > base64_iterator;

    copy(
        base64_iterator(BOOST_MAKE_PFTO_WRAPPER(istream_iterator<char>(cin))),
        base64_iterator(BOOST_MAKE_PFTO_WRAPPER(istream_iterator<char>())),
        ostream_iterator<char>(cout)
    );  
}

このように、標準入力を base64 に変換して標準出力に出すくらいだったら、 1 ステートメントで書ける

ちょっと解説

transform_width

transform_width, 6, 8> は istream_iterator を 8 bit の数値列として、 6 bit ずつの数値をイテレーションする。
以下のような感じ

#include <iostream>
#include <boost/pfto.hpp>
#include <boost/archive/iterators/transform_width.hpp>

int main()
{
    using namespace std;
    using namespace boost::archive::iterators;

    unsigned char buf[] = { 0xff, 0xff, 0x00 };

    transform_width<unsigned char *, 6, 8 > it(BOOST_PFTO_WRAPPER(buf));

    // input 11111111 11111111 00000000
    // output 111111 111111 111100 000000

    cout << static_cast<int>(*it) << endl; // => 63 (00111111)
    ++it;
    cout << static_cast<int>(*it) << endl; // => 63 (00111111)
    ++it;
    cout << static_cast<int>(*it) << endl; // => 60 (00111100)
    ++it;
    cout << static_cast<int>(*it) << endl; // => 0  (00000000)
}
base64_iterator

6bit の数値から base64 の 1 文字をイテレーションする。

BOOST_PFTO_WRAPPER

これは、

template<class T> void f(T a)  { ... } //(どんな型でも OK)

template<class T> void f(T* a)  { ... } //(ポインタだけ )

のような関数テンプレートがあって f(&obj) とやったときにどっちのテンプレートを使っていいか分からないコンパイラのためにあるマクロ。
定義側を

template<class T> void f(BOOST_PFTO_WRAPPER(T) a)  { ... } //(PFTO_WRAPPER なやつだけ OK)

template<class T> void f(T* a)  { ... } //(ポインタだけ )

としておくと f(&obj) とやればポインタのほうだとわかるし、上のほうを呼びたければ f(BOOST_MAKE_PFTO_WRAPPER(obj)) と明示的にやってやればいい。