Visualization Tool Kit(VTK)など

×

動機

通信では一般にchar配列として送受信が行われる.
ここで,パラメータはコマンドごとにことなるケースを想定している.

例えばCommand Aでは char, int, float[4]のバイト列を送り,
Command Bでは int, int, intというフォーマットになっているとしよう.
パラメータの型や数のよらず同じ関数でデータ→バイナリ配列,また,その逆をできるようにしたい.

struct CommandA
{
  char data1;
  int  data2;
  std::array<float, 4> data3;
};

struct CommandB
{
  int data1;
  int data2;
  int data3;
};

void func()
{
  // 目標とするインターフェイス
  CommandA a = {'A', 1234, {0.1, 0.2, 0.3, 0.4}}
  std::vector<char> binary_data_A = to_binary(a.data1, a.data2, a.data3, a.data4);

  CommandB b = { 10, 100, 1000 };
  std::vector<char> binary_data_B = to_binary(b.data1, b.data2, b.data3);

  std::tuple<char, int, std::array<float, 4>> a2 = from_binary<char, int, std::array<float, 4>>(binary_data_A);
  std::tuple<int, int, int> b2 = from_binary<int, int, int>(binary_data_B);
}


任意の型が任意の数続くという仕様に対してC++11で採択された可変テンプレート引数(Vardiadic Template)を用いる.
  • 本クラスは構造体アラインメントを考慮していない.
  • 本クラスは環境に依存したエンディアンとなる.

POD型→バイナリ変換器

template<template <typename T, typename A = std::allocator<T>> class Container = std::vector>
class to_binary {
public:
  typedef typename Container<char> container_type;

  template <typename ... types>
  static container_type convert(types ... others) {
    to_binary converter;
    converter.to_binary_impl(others...);
    return converter.res;
  }

private:
  // ... の中身がなくなるまで,テンプレートパラメータパックを展開しながら再帰
  template<typename T, typename ... types>
  typename std::enable_if<(sizeof ...(types) > 0)>::type to_binary_impl(T val, types ... others) {
    // 先頭の一つをTで受けて展開
    char* pointer = reinterpret_cast<char*>(&val);
    res.insert(res.end(), pointer, pointer + sizeof(T));
    to_binary_impl(others...);
  }

  // SFINAEにより ... の中身が0になるとこちらに来る.最後の一個を展開して終了
  template<typename T>
  void to_binary_impl(T val) {
    char* pointer = reinterpret_cast<char*>(&val);
    res.insert(res.end(), pointer, pointer + sizeof(T));
  }

  container_type res;
};

// test
int main()
{
  uint8_t a = 0x12;
  uint16_t b = 0x3456;
  std::array<uint32_t, 3> c = { 0x789abcde, 0xf0123456, 0xFFFFFFFF };

  // value -> char array
  auto binary = to_binary<>::convert(/* uint8_t */ a, /* uint16_t */ b, /* std::array<uint32_t, 3> */ c);

  std::array<char, 1 + 2 + 12> expected = {
    0x12,
    0x56, 0x34,
    0xde, 0xbc, 0x9a, 0x78,
    0x56, 0x34, 0x12, 0xf0,
    0xff, 0xff, 0xff, 0xff
  };

  assert(expected.size() == binary.size());
  for (int i = 0; i < expected.size(); ++i)
  {
    assert(binary[i] == expected[i]);
  }
  return 0;
}

逆変換器

テンプレート引数で指定した任意の数の型を持つtupleにバイナリ配列を展開する.

template<template <typename T, typename A = std::allocator<T>> class Container = std::vector>
class from_binary
{
public:
  typedef Container<char> container_type;
  typedef typename container_type::const_iterator const_iterator;

  template <typename ... types>
  static std::tuple<types...> convert(container_type const& binary_data)
  {
    return exec<types...>(binary_data.begin());
  }

private:
  template <typename T, typename ... types>
  static typename std::enable_if<(sizeof...(types) > 0), std::tuple<T, types...>>::type exec(const_iterator& first)
  {
    T val;
    std::copy(first, first + sizeof(T), reinterpret_cast<char*>(&val));
    first += sizeof(T);
    return std::tuple_cat(std::tuple<T>(std::move(val)), exec<types...>(first));
  }

  template <typename T>
  static std::tuple<T> exec(const_iterator& first)
  {
    T val;
    std::copy(first, first + sizeof(T), reinterpret_cast<char*>(&val));
    first += sizeof(T);
    return std::tuple<T>(std::move(val));
  }
};

// test
int main()
{
  std::vector<char> binary{
    0x12, 0x56, 0x34,(char)0xde, (char)0xbc, (char)0x9a, 0x78, 0x56, 0x34, 0x12, (char)0xf0, (char)0xff, (char)0xff, (char)0xff, (char)0xff 
  };

  // char array -> value
  auto tuple = from_binary<>::convert<uint8_t, uint16_t, std::array<uint32_t, 3>>(binary);

  assert(std::get<0>(tuple) == 0x12);
  assert(std::get<1>(tuple) == 0x3465);
  assert(std::get<2>(tuple)[0] == 0x789abcde);
  assert(std::get<2>(tuple)[1] == 0xf0123456);
  assert(std::get<2>(tuple)[2] == 0xffffffff);
}

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Menu

メニュー

チュートリアル

アルゴリズム(数学)

並列計算

STL

#include<memory> #include<string> #include<sstream> #include<algorithm> #include<functional> #include<numeric>

Media Foundation

【メニュー編集】
Wiki記法ガイド

メンバーのみ編集できます

広告募集中