Last active
February 15, 2016 14:45
-
-
Save TABETA/061022333abc7c428d5c to your computer and use it in GitHub Desktop.
reinterpret_castを使いたくないお ref: http://qiita.com/abedominal/items/c79cc7a04afca43ebc41
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
0:波動砲, 0.00845191 | |
1:波動砲, 0.00913878 | |
2:波動砲, 0.00815516 | |
続行するには何かキーを押してください . . . |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Union: 0.098571, 波動砲 | |
Direct: 0.098712, 波動砲 | |
Convert: 0.098260, 波動砲 | |
Void: 0.097815, 波動砲 | |
OffsetMemcpy: 1.100283, 波動砲 | |
OffsetShift: 0.278266, 波動砲 | |
続行するには何かキーを押してください . . . |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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