LoginSignup
36
33

More than 5 years have passed since last update.

RubyとC++でMessagePack

Last updated at Posted at 2014-05-21

C++のプログラムとRubyのプログラムの間でオブジェクトをやり取りする必要があったので、MessagePackを試した。

MessagePackとは

  • オブジェクトシリアライズフォーマット
  • 簡単に言うとバイナリのJSON。JSONのようにスキーマレスで使えるが、バイナリファイルなので圧縮効率が良い。
  • 様々な言語でAPIが用意されており、複数の言語での情報のやり取りにも使える。
  • 本家のページはこちら

Ruby APIのインストール方法

gemをインストールするだけ。

gem install msgpack

Rubyのサンプルコードはこのようになる。JSONのダンプ、ロードと同じくらいの気軽さで使える。

require 'msgpack'
msg = [1,2,3].to_msgpack  #=> "\x93\x01\x02\x03"
MessagePack.unpack(msg)   #=> [1,2,3]

C++ APIのインストール方法

githubのプロジェクトのページはこちら
このページに簡単なチュートリアルもある。

Macであればhomebrewで非常に簡単にインストールできる。/usr/local 以下にインストールされる。

brew install msgpack
g++ myfile.cpp -lmsgpack -o myfile.out

でコンパイルできる。

さらに、自前のクラスをダンプするときに便利なマクロ MSGPACK_DEFINE がある。

class myclass {
private:
    std::string m_str;
    std::vector<int> m_vec;
public:
    MSGPACK_DEFINE(m_str, m_vec);
    void Print() {
      std::cout << m_str << std::endl;
      for( std::vector<int>::iterator it = m_vec.begin(); it != m_vec.end(); ++it) {
        std::cout << *it << std::endl;
      }
    }
    myclass() {}
    myclass(const std::string & str, int max) {
      m_str = str;
      for( int i=0; i < max; i++) {
        m_vec.push_back(i);
      }
    }
};

このようなクラスがあったときに、

        std::vector<myclass> vec;
        // add some elements into vec...
        vec.push_back( myclass("foo", 3) );
        vec.push_back( myclass("bar", 0) );
        vec.push_back( myclass("baz", 2) );
        // you can serialize myclass directly
        msgpack::sbuffer sbuf;
        msgpack::pack(sbuf, vec);

このように簡単にシリアライズできる。デシリアライズも同様に簡単。
詳しくは本家のQuick Start を参照のこと。

C++からRubyにデータを渡す

#include <string>
#include <iostream>
#include <fstream>
#include <msgpack.hpp>

int main() {

  msgpack::type::tuple<int, bool, std::string> src(1, true, "example");
  std::ofstream ofs("data.mpac");
  msgpack::pack( ofs, src );

  return 0;
}
require 'msgpack'
MessagePack.unpack( File.open("data.mpac") )   #=> [1, true, "example"]

RubyからC++にデータを渡す

File.open('data.mpac','w') {|io| io.print [1,true,"example"].to_msgpack }
#include <string>
#include <iostream>
#include <iterator>
#include <fstream>
#include <msgpack.hpp>

int main() {

  std::ifstream ifs("data.mpac");
  std::istream_iterator<char> first(ifs);
  std::istream_iterator<char> last;

  const std::string data(first, last);  // read file

  msgpack::unpacked msg;
  msgpack::unpack( &msg, data.data(), data.size() );

  msgpack::object obj = msg.get();
  std::cout << obj << std::endl;   // => [1, true, "example"]

  msgpack::type::tuple<int, bool, std::string> converted;
  obj.convert(&converted);
  std::cout << converted.get<0>() << std::endl;  // => 1
  std::cout << converted.get<1>() << std::endl;  // => 1
  std::cout << converted.get<2>() << std::endl;  // => "example"

  return 0;
}

RubyのHashをC++でデシリアライズする

File.open('data.mpac','w') { |io| io.print ({foo: 1.25, bar: "example", baz: true}).to_msgpack }
#include <string>
#include <iostream>
#include <iterator>
#include <fstream>
#include <msgpack.hpp>

int main() {

  std::ifstream ifs("data.mpac");
  std::istream_iterator<char> first(ifs);
  std::istream_iterator<char> last;

  const std::string data(first, last);  // read file

  msgpack::unpacked msg;
  msgpack::unpack( &msg, data.data(), data.size() );

  msgpack::object obj = msg.get();
  std::cout << obj << std::endl;

  typedef std::map< std::string, msgpack::object > MapStrMsgpackObj;
  MapStrMsgpackObj mmap = obj.as<MapStrMsgpackObj>();
  std::cout << mmap.find("foo")->second.as<double>() << std::endl;      // => 1.25
  std::cout << mmap.find("bar")->second.as<std::string>() << std::endl; // => "example"
  std::cout << mmap.find("baz")->second.as<bool>() << std::endl;        // => 1

  return 0;
}

rubyのHashのkeyはstring型とする。(上のコードはキーがシンボルだが、msgpackに変換されたときにstringになる。)

36
33
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
33