Skip to content

Instantly share code, notes, and snippets.

@TABETA
Last active February 15, 2016 14:45
Show Gist options
  • Save TABETA/061022333abc7c428d5c to your computer and use it in GitHub Desktop.
Save TABETA/061022333abc7c428d5c to your computer and use it in GitHub Desktop.
reinterpret_castを使いたくないお ref: http://qiita.com/abedominal/items/c79cc7a04afca43ebc41
#pragma once
#include <string>
#include <iostream>
#include <cstdint>
#include <iosfwd>
struct Result
{
Result()
:requestStatus()
, optionCode()
, count()
{}
friend ostream& operator<<(ostream& os, const Result& r);
uint16_t requestStatus;
uint16_t optionCode;
uint16_t count;
};
ostream& operator<<(ostream& os, const Result& r)
{
string res;
uint16_t t = r.requestStatus;
res += static_cast<char>(t);
res += static_cast<char>(*(reinterpret_cast<char*>(&t) + 1));
t = r.optionCode;
res += static_cast<char>(t);
res += static_cast<char>(*(reinterpret_cast<char*>(&t) + 1));
t = r.count;
res += static_cast<char>(t);
res += static_cast<char>(*(reinterpret_cast<char*>(&t) + 1));
os << res;
return os;
}
#pragma pack(1)
struct Header
{
static const int headerPaddingByte_ = 4;
uint16_t messageByte;
uint16_t optionByte;
size_t getMessageOffset()const
{
return sizeof(Header)+headerPaddingByte_;
}
size_t getOptionOffset()const
{
return sizeof(Header)+headerPaddingByte_ + messageByte;
}
size_t getFooterOffset()const
{
return sizeof(Header)+headerPaddingByte_ + messageByte + optionByte;
}
};
struct Message
{
uint16_t requestStatus;
uint8_t info1;
uint8_t info2;
uint8_t info3;
uint8_t info4;
};
struct Option
{
uint16_t optionCode;
uint8_t info1;
uint8_t info2;
uint8_t info3;
uint8_t info4;
};
struct Footer
{
uint16_t count;
uint8_t info1;
uint8_t info2;
uint8_t info3;
uint8_t info4;
};
template<typename T>
union BufferAccessor
{
public:
BufferAccessor(uint8_t* b)
{
head = b;
}
uint8_t* head;
T* data;
};
class HeaderAccessor
{
public:
HeaderAccessor(uint8_t* b) :h_(b){}
uint8_t* getMessage()
{
return h_.head + h_.data->getMessageOffset();
}
uint8_t* getOption()
{
return h_.head + h_.data->getOptionOffset();
}
uint8_t* getFooter()
{
return h_.head + h_.data->getFooterOffset();
}
private:
BufferAccessor<Header> h_;
};
#pragma pack()
//Unionで頑張る
class BufferAnalyzeUnion
{
public:
void operator()(uint8_t* b, Result & r)
{
HeaderAccessor h(b);
BufferAccessor<Message> m(h.getMessage());
r.requestStatus = m.data->requestStatus;
BufferAccessor<Option> o(h.getOption());
r.optionCode = o.data->optionCode;
BufferAccessor<Footer> f(h.getFooter());
r.count = f.data->count;
}
};
//直接読み出す
class BufferAnalyzeDirect
{
public:
static const size_t msgOfs_ = offsetof(Header, messageByte);
static const size_t optOfs_ = offsetof(Header, optionByte);
void operator()(uint8_t* b, Result & r)
{
r.requestStatus = *reinterpret_cast<uint16_t*>(&b[4 + 4]);
uint16_t msgByte = *reinterpret_cast<uint16_t*>(&b[msgOfs_]);
r.optionCode = *reinterpret_cast<uint16_t*>(&b[4 + 4 + msgByte]);
uint16_t optByte = *reinterpret_cast<uint16_t*>(&b[optOfs_]);
r.count = *reinterpret_cast<uint16_t*>(&b[4 + 4 + msgByte + optByte]);
}
};
//一回ずつフレーム情報を表現する構造体のポインタに変換する方式
class BufferAnalyzeConvert
{
public:
void operator()(uint8_t* b, Result & r)
{
Header* h = reinterpret_cast<Header*>(b);
Message* m = reinterpret_cast<Message*>(&b[sizeof(Header)+Header::headerPaddingByte_]);
r.requestStatus = m->requestStatus;
Option* o = reinterpret_cast<Option*>(&b[sizeof(Header)+Header::headerPaddingByte_ + h->messageByte]);
r.optionCode = o->optionCode;
Footer* f = reinterpret_cast<Footer*>(&b[sizeof(Header)+Header::headerPaddingByte_ + h->messageByte + h->optionByte]);
r.count = f->count;
}
};
//void
class BufferAnalyzeVoid
{
public:
void operator()(uint8_t* b, Result & r)
{
Header* h = static_cast<Header*>(static_cast<void*>(b));
Message* m = static_cast<Message*>(static_cast<void*>(&b[sizeof(Header)+Header::headerPaddingByte_]));
r.requestStatus = m->requestStatus;
Option* o = static_cast<Option*>(static_cast<void*>(&b[sizeof(Header)+Header::headerPaddingByte_ + h->messageByte]));
r.optionCode = o->optionCode;
Footer* f = static_cast<Footer*>(static_cast<void*>(&b[sizeof(Header)+Header::headerPaddingByte_ + h->messageByte + h->optionByte]));
r.count = f->count;
}
};
//Offsetでデータの位置を突き止めてmemcpyする
class BufferAnalyzeOffsetMemcpy
{
public:
static const size_t messageByteSize_ = sizeof(((Header*)0)->messageByte);
static const size_t optionByteSize_ = sizeof(((Header*)0)->optionByte);
static const size_t requestStatusSize_ = sizeof(((Message*)0)->requestStatus);
static const size_t optionCodeSize_ = sizeof(((Option*)0)->optionCode);
static const size_t countSize_ = sizeof(((Footer*)0)->count);
void operator()(uint8_t* b, Result & r)
{
size_t msgByte = 0;
size_t optByte = 0;
memcpy(&msgByte, &b[offsetof(Header, messageByte)], messageByteSize_);
memcpy(&optByte, &b[offsetof(Header, optionByte)], optionByteSize_);
memcpy(&r.requestStatus,&b[sizeof(Header)+Header::headerPaddingByte_ + offsetof(Message, requestStatus)], requestStatusSize_);
memcpy(&r.optionCode, &b[sizeof(Header)+Header::headerPaddingByte_ + msgByte + offsetof(Option, optionCode) ], optionCodeSize_);
memcpy(&r.count, &b[sizeof(Header)+Header::headerPaddingByte_ + msgByte + optByte + offsetof(Footer, count) ], countSize_);
}
};
//Offsetでデータの位置を突き止めてシフト演算で復元する
class BufferAnalyzeOffsetShift
{
public:
static const size_t messageByteSize_ = sizeof(((Header*)0)->messageByte);
static const size_t optionByteSize_ = sizeof(((Header*)0)->optionByte);
static const size_t requestStatusSize_ = sizeof(((Message*)0)->requestStatus);
static const size_t optionCodeSize_ = sizeof(((Option*)0)->optionCode);
static const size_t countSize_ = sizeof(((Footer*)0)->count);
void operator()(uint8_t* b, Result & r)
{
size_t msgByte = 0;
size_t optByte = 0;
#define get(a) b[a] + (b[a + 1] << 8)
msgByte = get(offsetof(Header, messageByte));
optByte = get(offsetof(Header, optionByte));
r.requestStatus = get(sizeof(Header)+Header::headerPaddingByte_ + offsetof(Message, requestStatus));
r.optionCode = get(sizeof(Header)+Header::headerPaddingByte_ + msgByte + offsetof(Option, optionCode));
r.count = get(sizeof(Header)+Header::headerPaddingByte_ + msgByte + optByte + offsetof(Footer, count));
#undef get
}
};
#include <string>
#include <iostream>
#include <chrono>
#include <windows.h>
using namespace std;
using namespace std::chrono;
namespace TimerType
{
class CrossPlatform
{
public:
void start()
{
start_ = system_clock::now();
}
double elapsed() const
{
duration<double> d = system_clock::now() - start_;
return d.count();
}
private:
system_clock::time_point start_;
};
class HighAccuracy
{
public:
void start()
{
if (!QueryPerformanceFrequency(&freq_)) throw;
if (!QueryPerformanceCounter(&start_)) throw;
}
double elapsed() const
{
LARGE_INTEGER end;
if (!QueryPerformanceCounter(&end)) throw;
return static_cast<double>(end.QuadPart - start_.QuadPart) / freq_.QuadPart;
}
private:
LARGE_INTEGER freq_;
LARGE_INTEGER start_;
};
}
template<typename T>
class Timer
{
public:
Timer()
{
timer_.start();
}
void start()
{
timer_.start();
}
double elapsed() const
{
return timer_.elapsed();
}
private:
T timer_;
};
struct Result
{
Result()
:requestStatus()
, optionCode()
, count()
{}
friend ostream& operator<<(ostream& os, const Result& r);
uint16_t requestStatus;
uint16_t optionCode;
uint16_t count;
};
ostream& operator<<(ostream& os, const Result& r)
{
string res;
uint16_t t = r.requestStatus;
res += static_cast<char>(t);
res += static_cast<char>(*(reinterpret_cast<char*>(&t) + 1));
t = r.optionCode;
res += static_cast<char>(t);
res += static_cast<char>(*(reinterpret_cast<char*>(&t) + 1));
t = r.count;
res += static_cast<char>(t);
res += static_cast<char>(*(reinterpret_cast<char*>(&t) + 1));
os << res;
return os;
}
#pragma pack(1)
struct Header
{
static const int headerPaddingByte_ = 4;
uint16_t messageByte;
uint16_t optionByte;
size_t getMessageOffset()const
{
return sizeof(Header)+headerPaddingByte_;
}
size_t getOptionOffset()const
{
return sizeof(Header)+headerPaddingByte_ + messageByte;
}
size_t getFooterOffset()const
{
return sizeof(Header)+headerPaddingByte_ + messageByte + optionByte;
}
};
struct Message
{
uint16_t requestStatus;
uint8_t info1;
uint8_t info2;
uint8_t info3;
uint8_t info4;
};
struct Option
{
uint16_t optionCode;
uint8_t info1;
uint8_t info2;
uint8_t info3;
uint8_t info4;
};
struct Footer
{
uint16_t count;
uint8_t info1;
uint8_t info2;
uint8_t info3;
uint8_t info4;
};
template<typename T>
union BufferAccessor
{
public:
BufferAccessor(uint8_t* b)
{
head = b;
}
uint8_t* head;
T* data;
};
class HeaderAccessor
{
public:
HeaderAccessor(uint8_t* b) :h_(b){}
uint8_t* getMessage()
{
return h_.head + h_.data->getMessageOffset();
}
uint8_t* getOption()
{
return h_.head + h_.data->getOptionOffset();
}
uint8_t* getFooter()
{
return h_.head + h_.data->getFooterOffset();
}
private:
BufferAccessor<Header> h_;
};
#pragma pack()
void setup(uint8_t* buffer, size_t e)
{
for (size_t i = 0; i < e;++i)
{
buffer[i] = i;
}
uint16_t* messageByte = reinterpret_cast<uint16_t*>(&buffer[0]);
*messageByte = 32;
uint16_t* optionByte = reinterpret_cast<uint16_t*>(&buffer[2]);
*optionByte = 32;
buffer[4 + 4] = -108;
buffer[4 + 4 + 1] = 103;
buffer[4 + 4 + 32] = -109;
buffer[4 + 4 + 32 + 1] = -82;
buffer[4 + 4 + 32 + 32] = -106;
buffer[4 + 4 + 32 + 32 + 1] = 67;
}
int main(int argv, char* argc[])
{
static const int rep = 10000000;
static const int testNum = 3;
uint8_t sampleData[1024] = {};
setup(sampleData, sizeof(sampleData) / sizeof(sampleData[0]));
Timer<TimerType::HighAccuracy>* timer[testNum];
Result result[testNum];
double tim[testNum];
int j;
//Unionで頑張る
j = 0;
timer[j] = new Timer<TimerType::HighAccuracy>();
for (int i = 0; i < rep; ++i)
{
HeaderAccessor h(sampleData);
BufferAccessor<Message> m(h.getMessage());
result[j].requestStatus = m.data->requestStatus;
BufferAccessor<Option> o(h.getOption());
result[j].optionCode = o.data->optionCode;
BufferAccessor<Footer> f(h.getFooter());
result[j].count = f.data->count;
}
tim[j] = timer[j]->elapsed();
//直接読み出す
j = 1;
timer[j] = new Timer<TimerType::HighAccuracy>();
for (int i = 0; i < rep; ++i)
{
result[j].requestStatus = *reinterpret_cast<uint16_t*>(&sampleData[4 + 4]);
result[j].optionCode = *reinterpret_cast<uint16_t*>(&sampleData[4 + 4 + 32]);
result[j].count = *reinterpret_cast<uint16_t*>(&sampleData[4 + 4 + 32 + 32]);
}
tim[j] = timer[j]->elapsed();
//一回ずつフレーム情報を表現する構造体のポインタに変換する方式
j = 2;
timer[j] = new Timer<TimerType::HighAccuracy>();
for (int i = 0; i < rep; ++i)
{
Header* h = reinterpret_cast<Header*>(sampleData);
Message* m = reinterpret_cast<Message*>(&sampleData[sizeof(Header)+Header::headerPaddingByte_]);
result[j].requestStatus = m->requestStatus;
Option* o = reinterpret_cast<Option*>(&sampleData[sizeof(Header) + Header::headerPaddingByte_ + h->messageByte]);
result[j].optionCode = o->optionCode;
Footer* f = reinterpret_cast<Footer*>(&sampleData[sizeof(Header)+Header::headerPaddingByte_ + h->messageByte + h->optionByte]);
result[j].count = f->count;
}
tim[j] = timer[j]->elapsed();
for (int i = 0; i < testNum; ++i)
{
cout << i << ":" << result[i] << ", " << tim[i] << endl;
delete timer[i];
}
return 0;
}
0:波動砲, 0.00845191
1:波動砲, 0.00913878
2:波動砲, 0.00815516
続行するには何かキーを押してください . . .
Union: 0.098571, 波動砲
Direct: 0.098712, 波動砲
Convert: 0.098260, 波動砲
Void: 0.097815, 波動砲
OffsetMemcpy: 1.100283, 波動砲
OffsetShift: 0.278266, 波動砲
続行するには何かキーを押してください . . .
#include <iostream>
#include "Timer.hpp"
#include "Buffer.hpp"
template<typename T, typename U>
class Measure
{
static const uint64_t rep = 100000000;
U r_;
public:
Measure() :r_()
{}
U get()
{
return r_;
}
double execute(uint8_t* buffer)
{
Timer<TimerType::HighAccuracy> timer;
for (uint64_t i = 0; i < rep; ++i)
{
T()(buffer, r_);
}
return timer.elapsed();
}
};
void setup(uint8_t* buffer, size_t e)
{
for (size_t i = 0; i < e; ++i)
{
buffer[i] = i;
}
uint16_t* messageByte = reinterpret_cast<uint16_t*>(&buffer[0]);
*messageByte = 32;
uint16_t* optionByte = reinterpret_cast<uint16_t*>(&buffer[2]);
*optionByte = 32;
buffer[4 + 4] = -108;
buffer[4 + 4 + 1] = 103;
buffer[4 + 4 + 32] = -109;
buffer[4 + 4 + 32 + 1] = -82;
buffer[4 + 4 + 32 + 32] = -106;
buffer[4 + 4 + 32 + 32 + 1] = 67;
}
#include <iomanip>
#define measure(n,m,v) \
{ \
Measure<n##m, Result> a; \
volatile double r = a.execute(v); \
auto c = a.get(); \
cout << setiosflags(ios::left) << setw(15) << #m":" << fixed << setprecision(6) << r << ", " << c << endl; \
}
int main(int argv, char* argc[])
{
uint8_t sampleData[1024] = {};
setup(sampleData, sizeof(sampleData) / sizeof(sampleData[0]));
measure(BufferAnalyze, Union, sampleData);
measure(BufferAnalyze, Direct, sampleData);
measure(BufferAnalyze, Convert, sampleData);
measure(BufferAnalyze, Void, sampleData);
measure(BufferAnalyze, OffsetMemcpy, sampleData);
measure(BufferAnalyze, OffsetShift, sampleData);
return 0;
}
#pragma once
#include <chrono>
#include <windows.h>
using namespace std;
using namespace std::chrono;
namespace TimerType
{
class CrossPlatform
{
public:
void start()
{
start_ = system_clock::now();
}
double elapsed() const
{
duration<double> d = system_clock::now() - start_;
return d.count();
}
private:
system_clock::time_point start_;
};
class HighAccuracy
{
public:
void start()
{
if (!QueryPerformanceFrequency(&freq_)) throw;
if (!QueryPerformanceCounter(&start_)) throw;
}
double elapsed() const
{
LARGE_INTEGER end;
if (!QueryPerformanceCounter(&end)) throw;
return static_cast<double>(end.QuadPart - start_.QuadPart) / freq_.QuadPart;
}
private:
LARGE_INTEGER freq_;
LARGE_INTEGER start_;
};
}
template<typename T>
class Timer
{
public:
Timer() :timer_()
{
timer_.start();
}
void start()
{
timer_.start();
}
double elapsed() const
{
return timer_.elapsed();
}
private:
T timer_;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment