前回の「微小時間刻み運動の要素をクラス化してみる」で微小時間刻み運動の要素をクラス化してみたが、どうにも使い勝手が悪そうなので、何かできないかと色々試した見ることにした。
ひとまず、データの柔軟性と将来的にOpenCLで並列処理をする際のデータの受け渡しなどを考えて、要素クラスからデータの実体を分離してみることにした。メインロジックとしては要素クラスを通してデータを操作するが、並列処理をする場合は全要素についてフラットなデータ空間の方が扱いやすいのではないかという予想してみた。なんか前にチラッと見たデザインパターンのフライウェイトとかにも近いような気がする。当然データを分離しているので、タイムステップの更新の際に実データの移動は発生せず、フライウェイトパターンと同じような利点もあると予想している。
実際のコードは次のようになっている。
- constant.hpp
#ifndef __CONSTANT_HPP__ #define __CONSTANT_HPP__ namespace DECS{ // Constants for General typedef const unsigned int id_t; typedef const unsigned int dim_t; id_t DEFAULT_DIMENSION = 3; enum AXIS{ X, Y, Z }; enum RAXIS{ RX, RY, RZ }; // Constants for DataStore typedef unsigned int n_parameter_t; const n_parameter_t DEFAULT_PARAMETER_NUMBERS = 7; typedef unsigned int data_size_t; const data_size_t DEFAULT_DATASTORE_SIZE = 10; typedef unsigned int index_t; } #endif // __CONSTANT_HPP__
- DataStore.hpp
#ifndef __DATASTORE_HPP__ #define __DATASTORE_HPP__ #include <decs/constant.hpp> namespace DECS{ class DataStore{ private: data_size_t size_; data_size_t wholeSize_; dim_t dim_; n_parameter_t nParam_; double* data_; protected: void fillZero(); public: DataStore(); DataStore(data_size_t size, dim_t dim, n_parameter_t nParam); DataStore(const DataStore& obj); ~DataStore(); double* getStorePtr(); double* getStorePtr(id_t id, index_t index); DataStore operator=(const DataStore& obj) const; }; } #endif // __DATASTORE_HPP__
- DataStore.cpp
#include <decs/DataStore.hpp> namespace DECS{ DataStore::DataStore() : size_(DEFAULT_DATASTORE_SIZE), dim_(DEFAULT_DIMENSION), nParam_(DEFAULT_PARAMETER_NUMBERS) { this->wholeSize_ = this->size_ * this->dim_ * this->nParam_; this->data_ = new double[this->wholeSize_]; this->fillZero(); } DataStore::DataStore(data_size_t size, dim_t dim, n_parameter_t nParam) : size_(size), dim_(dim), nParam_(nParam) { this->wholeSize_ = this->size_ * this->dim_ * this->nParam_; this->data_ = new double[this->wholeSize_]; this->fillZero(); } DataStore::DataStore(const DataStore& obj) : size_(obj.size_), dim_(obj.dim_), nParam_(obj.nParam_), wholeSize_(obj.wholeSize_) { this->wholeSize_ = this->size_ * this->dim_ * this->nParam_; this->data_ = new double[this->wholeSize_]; for(data_size_t i = 0; i < this->wholeSize_; i++){ this->data_[i] = obj.data_[i]; } } DataStore::~DataStore() { delete [] this->data_; } void DataStore::fillZero() { for(data_size_t i = 0; i < this->wholeSize_; i++){ this->data_[i] = 0.0; } } double* DataStore::getStorePtr() { return this->data_; } double* DataStore::getStorePtr(id_t id, index_t index) { if(id <= this->size_ && index <= this->nParam_){ return this->data_ + id * this->nParam_ * this->dim_ + index * this->dim_; } return 0; } DataStore DataStore::operator=(const DataStore& obj) const { DataStore rtn(obj); return rtn; } }
constant.hppは単純に定数や列挙体をまとめて定義しているだけのヘッダーファイルとなっている。データ自体はdata_として1次元の配列として保持していて、getStorePtr(id_t id, index_t index)でid番目の要素のindex番目の3次元ベクトル(デフォルトでは)パラメータのポインターを渡すようにした。
また、OpenCLにフラットなデータを渡せるようにgetStorePtr()でdata_の先頭のポインターを渡すようにしている。ただ、ポインターを渡してしまうならクラスじゃなくて構造体でいいのではないかとう気もする。うーん。
コピーコンストラクタとオペレータ"="は結果出力時にデータを対比することを想定している。
なんかおとなしくstd::vectorを使えばいいじゃないかという気もするが、std::vectorってそのままじゃOpenCLカーネルには渡せない気がするし、いちいちデータを作っていたらそれはそれでオーバーヘッドになるなと思うしで、色々迷うところだ。
コメント