Boost 1.55 버전 기준으로 작성했습니다.
#include <boost/thread.hpp>
#include <boost/lockfree/queue.hpp>
#include <boost/format.hpp>
#include <boost/bind.hpp>
#include <boost/serialization/singleton.hpp>
#include <iostream>
#include <queue>
#include "IOCPQueue.h"
void wait(int seconds)
{
boost::this_thread::sleep( boost::posix_time::seconds( seconds ) );
}
void thread_func()
{
for( int i = 0; i < 5; ++i )
{
wait(1);
std::cout<< i << std::endl;
}
}
void thread_test1()
{
boost::thread t(thread_func);
t.join(); // thread 가 종료될때까지 blocking 된다.
}
void thread_func2()
{
try
{
for( int i = 0; i < 5; ++i )
{
wait(1);
std::cout<<"thread:"<<boost::this_thread::get_id()<<" "<<i<<std::endl;
}
}
catch( boost::thread_interrupted&)
{
std::cout << "thread interrupted" << std::endl;
}
}
void thread_test2()
{
std::cout << boost::thread::hardware_concurrency() << std::endl;
std::cout<<"(main)thread main id"<< boost::this_thread::get_id() << std::endl;
boost::thread t(thread_func2);
std::cout<<"(main)thread id"<< t.get_id() << std::endl;
wait(3);
t.interrupt();
t.join();
}
bool g_bPlay = true;
boost::lockfree::queue< int > g_Queue(100);
void push_worker( int add )
{
int i = 0;
while(g_bPlay)
{
//wait(3);
while(g_Queue.push( i ))
std::cout << boost::format("push %d") % i << std::endl;
i += add;
}
}
void pop_worker()
{
while(g_bPlay)
{
int n;
if( g_Queue.pop( n ) )
{
wait(2);
std::cout << boost::format("pop %d") % n << std::endl;
}
}
}
void thread_safe_queue_test()
{
boost::thread_group tg;
tg.add_thread( new boost::thread( push_worker, 1 ) );
wait(1);
tg.add_thread( new boost::thread( push_worker, 2 ) );
wait(1);
tg.add_thread( new boost::thread(pop_worker) );
tg.join_all();
}
class stlQueue //: boost::<boost::mutex>
{
private:
boost::mutex m_mtx;
std::queue< int > m_queue;
// boost::lock_guard<boost::mutex> lock(m_mtx);
public:
stlQueue() { }
void push( int i )
{
boost::lock_guard<boost::mutex> lock(m_mtx);
m_queue.push( i );
}
int pop()
{
boost::lock_guard<boost::mutex> lock(m_mtx);
if( m_queue.empty() )
return -1;
int v = m_queue.front();
m_queue.pop();
return v;
}
bool empty()
{
boost::lock_guard<boost::mutex> lock(m_mtx);
return m_queue.empty();
}
};
SFIOCPQueue< int > m_iocpQueue;
stlQueue m_stlQueue;
boost::lockfree::queue< int > m_boostQueue(128);
boost::atomic_int producer_count(0);
boost::atomic_int consumer_count(0);
const int iterations = 10000000;
const int producer_thread_count = 8;
const int consumer_thread_count = 1;
// 1:1 의 경우 lock-free 가 빠름
// 2:1 의 경우 lock free 가 빠름
// 3:1 의 경우 lock free 가 빠름
// 4:1 의 경우 lock free 가 빠름
void producer_iocpqueue(void)
{
std::cout<<"thread id"<< boost::this_thread::get_id() << std::endl;
for( int i = 0; i != iterations; ++i )
{
int value = ++producer_count;
m_iocpQueue.Push( &value );
}
}
boost::atomic<bool> iocp_done(false);
void consumer_iocpqueue(void)
{
std::cout<<"thread id"<< boost::this_thread::get_id() << std::endl;
while(!iocp_done)
{
while(m_iocpQueue.Pop(0))
{
++consumer_count;
}
}
while(m_iocpQueue.Pop(0))
{
++consumer_count;
}
}
void producer_stlqueue(void)
{
std::cout<<"thread id"<< boost::this_thread::get_id() << std::endl;
for( int i = 0; i != iterations; ++i )
{
int value = ++producer_count;
m_stlQueue.push( value );
}
}
boost::atomic<bool> sql_done(false);
void consumer_stlqueue(void)
{
std::cout<<"thread id"<< boost::this_thread::get_id() << std::endl;
int value;
while(!sql_done)
{
while( m_stlQueue.pop() != -1 )
{
++consumer_count;
}
}
while(m_stlQueue.pop() != -1)
{
++consumer_count;
}
}
void producer_boostqueue(void)
{
std::cout<<"thread id"<< boost::this_thread::get_id() << std::endl;
for( int i = 0; i != iterations; ++i )
{
int value = ++producer_count;
while(!m_boostQueue.push(value))
;
}
}
boost::atomic<bool> boost_done(false);
void consumer_boostqueue(void)
{
std::cout<<"thread id"<< boost::this_thread::get_id() << std::endl;
int value;
while(!boost_done)
{
while( m_boostQueue.pop(value) )
++consumer_count;
}
while( m_boostQueue.pop(value) )
++consumer_count;
}
void queue_test()
{
// ipco queue
{
boost::progress_timer progress_t;
producer_count = 0;
consumer_count = 0;
boost::thread_group producer_threads, consumer_threads;
for( int i = 0; i != producer_thread_count; ++i )
producer_threads.create_thread( producer_iocpqueue );
for( int i = 0; i != consumer_thread_count; ++i )
consumer_threads.create_thread( consumer_iocpqueue );
producer_threads.join_all();
iocp_done = true;
consumer_threads.join_all();
std::cout << "IOCP Queue test" << std::endl;
std::cout << "IOCP Queue Producer cout : " << producer_count << std::endl;
std::cout << "IOCP Queue Consumer cout : " << consumer_count << std::endl;
}
// sql queue
{
boost::progress_timer progress_t;
producer_count = 0;
consumer_count = 0;
boost::thread_group producer_threads, consumer_threads;
for( int i = 0; i != producer_thread_count; ++i )
producer_threads.create_thread( producer_stlqueue );
for( int i = 0; i != consumer_thread_count; ++i )
consumer_threads.create_thread( consumer_stlqueue );
producer_threads.join_all();
sql_done = true;
consumer_threads.join_all();
std::cout << "sql Queue test" << std::endl;
std::cout << "sql Queue Producer cout : " << producer_count << std::endl;
std::cout << "sql Queue Consumer cout : " << consumer_count << std::endl;
}
// boost queue
{
boost::progress_timer progress_t;
producer_count = 0;
consumer_count = 0;
boost::thread_group producer_threads, consumer_threads;
for( int i = 0; i != producer_thread_count; ++i )
producer_threads.create_thread( producer_boostqueue );
for( int i = 0; i != consumer_thread_count; ++i )
consumer_threads.create_thread( consumer_boostqueue );
producer_threads.join_all();
boost_done = true;
consumer_threads.join_all();
std::cout << "boost Queue test" << std::endl;
std::cout << "boost Queue Producer cout : " << producer_count << std::endl;
std::cout << "boost Queue Consumer cout : " << consumer_count << std::endl;
}
}
boost::mutex m_mtx;
class MyThread
{
private:
int cnt;
public:
MyThread() { cnt = 0; }
void loop()
{
int cnt2 = 0;
for( cnt = 0; cnt < 50; ++cnt )
{
++cnt2;
//boost::lock_guard<boost::mutex> lock(m_mtx);
std::cout << "thread id"<< boost::this_thread::get_id() << " : " << cnt << std::endl;
boost::this_thread::sleep( boost::posix_time::millisec(500) );
}
}
};
void thread_member_function()
{
MyThread my, my2;
boost::thread_group tg;
tg.create_thread( boost::bind( &MyThread::loop, &my ) );
tg.create_thread( boost::bind( &MyThread::loop, &my ) );
tg.join_all();
}
void thread_test()
{
thread_member_function();
// queue_test();
// thread_safe_queue_test();
}
Boost Signals 샘플 (0) | 2016.01.31 |
---|---|
Boost Serializtion 샘플2 (0) | 2016.01.31 |
Boost Serialization 샘플 (0) | 2016.01.31 |
Boost Regex 실전 사용 샘플 (0) | 2016.01.31 |
Boost Regex(정규식) 샘플 (0) | 2016.01.31 |
Boost 1.55 버전 기준으로 작성했습니다.
#include <iostream>
#include <boost/function.hpp>
#include <vector>
#include <algorithm>
#include <boost/assign.hpp>
#include <boost/bind.hpp>
#include <boost/signals2.hpp>
#include <boost/shared_ptr.hpp>
//
// boost::sinals
// 개인적으로는 observer 패턴 구현시 유용하게 쓸듯
// 콜백 함수를 관리해 주고 shared_ptr과 연동시 메모리 추적 기능까지 있어서
// 아주 유용하게 쓰임
// function 에도 week_ptr을 사용하면 비슷하게 구현할 수 있으나
// 콜백으로 물린 signal들을 관리는 따로 해야하는므로 복수의 signal들을 관리할때 좋다.
struct HelloWord
{
float operator()( float a, float b ) const
{
std::cout<< "Hello Operator" << std::endl;
return a + b;
}
float add( float a, float b ) const
{
return a + b;
}
};
//
// 간단한 시그널 테스트
// 앞에서 봤던 function 과 비슷한 역활을 하는거 같지만
// 내부적으로 function container를 생성하여 관리하는 듯 보인다.
// 그래서 복수의 시그널 연결이 가능하다.
void Signal_Test()
{
HelloWord hello;
// float( float, float ) 시그니쳐를 갖는 시그널 생성
boost::signals2::signal< float ( float, float ) > sig;
// 시그널에 멤버 함수의 클래스 연결
sig.connect( boost::bind( &HelloWord::add, &hello, _1, _2 ) );
// 시그널 호출 그리고 반환값
float fValue = *sig( 1, 2 );
std::cout<< "시그날 값 : " << fValue << std::endl;
};
class Document
{
public:
typedef boost::signals2::signal< void () > signal_t;
public:
Document(){}
boost::signals2::connection connect( const signal_t::slot_type& subscriber )
{
return m_sig.connect( subscriber );
}
void append( const char* s )
{
m_text += s;
m_sig();
}
const std::string& getText() const
{
return m_text;
}
private:
signal_t m_sig;
std::string m_text;
};
class TextView
{
public:
TextView( Document& doc ) : m_document( doc )
{
m_connection = m_document.connect( boost::bind( &TextView::refresh, this ) );
}
void refresh() const
{
std::cout << "TextView: " << m_document.getText() << std::endl;
}
private:
Document& m_document;
boost::signals2::connection m_connection;
};
class HexView
{
public:
HexView( Document& doc ) : m_document( doc )
{
m_connection = m_document.connect( boost::bind( &HexView::refresh, this ) );
}
void refresh() const
{
const std::string& s = m_document.getText();
std::cout<< "HexView";
for( std::string::const_iterator it = s.begin(); it != s.end(); ++it )
std::cout << ' ' << std::hex << static_cast< int >( *it );
std::cout << std::endl;
}
private:
Document& m_document;
boost::signals2::connection m_connection;
};
// 리스너 형식으로 대체하여 사용할 수 있는 시그날!!
// 좋쿤
void Signal_Listener_Test()
{
Document doc;
TextView v1( doc );
HexView v2( doc );
doc.append( "Doc => View!" );
}
class NetCore
{
public:
NetCore() {}
~NetCore() {}
typedef boost::signals2::signal< void ( int, char* ) > signal_connect_t;
typedef boost::signals2::signal< void ( int ) > signal_error_code_t;
typedef signal_connect_t::slot_type connect_slot;
typedef signal_error_code_t::slot_type error_slot;
signal_connect_t m_connectSig;
signal_error_code_t m_errorSig;
boost::signals2::connection addOnConnect( const connect_slot& subscriber )
{
return m_connectSig.connect( subscriber );
}
boost::signals2::connection addOnError( const error_slot& subscriber )
{
return m_errorSig.connect( subscriber );
}
void onConnect( int hostID, char* s )
{
m_connectSig( hostID, s );
}
void onError( int errorCode )
{
m_errorSig( errorCode );
}
};
struct NetListener
{
public:
NetListener(){}
void onConnect( int nRemoteID, char* strRemoteIP )
{
std::cout<< "RemoteID: " << nRemoteID << " RemoteIP: " << strRemoteIP << std::endl;
}
void onErrorCode( int nErrorCode )
{
std::cout<< nErrorCode << std::endl;
}
};
//
// 메모리 추적 기능이 추가된 시그널
// 스마트 포인터를 사용해서 생성하고
// signal의 slot_type의 track() 함수를 이용하여
// 메모리 추적이 가능 slot_type 에 week_ptr로 연결되어
// 실제 메모리가 삭제되면 signals 내부에서 disconnect 되어 버린다.
void Signal_With_Trackable()
{
NetCore core;
boost::shared_ptr< NetListener > spListener( new NetListener() );
// 메모리 추적
core.addOnConnect( NetCore::connect_slot( &NetListener::onConnect, spListener.get(), _1, _2 ).track(spListener) );
core.addOnError( NetCore::error_slot( &NetListener::onErrorCode, spListener.get(), _1 ).track(spListener) );
core.onConnect( 1, "192.168.1.2" );
core.onError( 12 );
spListener.reset();
core.onConnect( 1, "192.168.1.2" );
core.onError( 12 );
};
Boost Thread 샘플 & Lock-Free Queue 성능 테스트 (0) | 2016.01.31 |
---|---|
Boost Serializtion 샘플2 (0) | 2016.01.31 |
Boost Serialization 샘플 (0) | 2016.01.31 |
Boost Regex 실전 사용 샘플 (0) | 2016.01.31 |
Boost Regex(정규식) 샘플 (0) | 2016.01.31 |
Boost 1.55 버전 기준으로 작성했습니다.
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/map.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/array.hpp>
#include <boost/iostreams/device/back_inserter.hpp>
#include <boost/pool/pool.hpp>
#include <boost/pool/object_pool.hpp>
#include <boost/pool/singleton_pool.hpp>
#include <boost/pool/pool_alloc.hpp>
#include <boost/timer.hpp>
#include <boost/progress.hpp>
#define SERIALIZATION_MACRO_BEGIN \
friend class boost::serialization::access; \
template< typename Archive > \
void serialize( Archive& ar, const unsigned int version ) \
{
#define SERIALIZATION_DERIVED(BASE_CLASS) \
ar & boost::serialization::base_object<BASE_CLASS>(*this);
#define SERIALIZE(DATA) \
ar & DATA;
#define SERIALIZATION_MACRO_END \
}
typedef std::vector< char, boost::fast_pool_allocator<char> > TEST_BUFFER_TYPE;
typedef boost::iostreams::back_insert_device< TEST_BUFFER_TYPE > TEST_STREAM_DEVICE;
typedef boost::iostreams::basic_array_source<char> TEST_ARRAY_DEVICE;
typedef boost::iostreams::stream< TEST_STREAM_DEVICE > TestOutStream;
typedef boost::iostreams::stream_buffer< TEST_ARRAY_DEVICE > TestInStream;
template <typename T> inline void SerializeObjectHelper(T const& obj, TEST_BUFFER_TYPE& buffer )
{
TestOutStream out_s_(buffer);
boost::archive::binary_oarchive out_ar_(out_s_);
out_ar_ << obj;
out_s_.flush();
}
template <typename T> inline void DeserializeObjectHelper(T& obj, char const* pRowData, size_t dataSize )
{
TestInStream in_s_(pRowData, dataSize);
boost::archive::binary_iarchive in_ar_(in_s_);
in_ar_ >> obj;
}
struct TestData
{
//std::vector< std::string > vDummyStrings;
int n1;
int n2;
int n3;
int n4;
float v1;
float v2;
float v3;
TestData()
{
n1 = 1;
n2 = 2;
n3 = 3;
v1 = 100.123123f;
v2 = 200.123f;
v3 = 65536.123123f;
}
SERIALIZATION_MACRO_BEGIN
//SERIALIZE(vDummyStrings)
SERIALIZE(n1)
SERIALIZE(n2)
SERIALIZE(n3)
SERIALIZE(n4)
SERIALIZE(v1)
SERIALIZE(v2)
SERIALIZE(v3)
SERIALIZATION_MACRO_END
};
struct TestDataDerived : public TestData
{
std::vector< float > vDummyfloat;
std::vector< int > vDummyint;
float v11;
float v22;
float v33;
TestDataDerived() {}
SERIALIZATION_MACRO_BEGIN
SERIALIZATION_DERIVED(TestData)
SERIALIZE(vDummyfloat)
SERIALIZE(vDummyint)
SERIALIZE(v11)
SERIALIZE(v22)
SERIALIZE(v33)
SERIALIZATION_MACRO_END
};
struct AddData
{
int a;
int b;
int c;
SERIALIZATION_MACRO_BEGIN
SERIALIZE(a)
SERIALIZE(b)
SERIALIZE(c)
SERIALIZATION_MACRO_END
};
void serialize2_main()
{
TestDataDerived data;
//vector< TestDataDerived > vTest;
for( int i = 0; i < 10; ++i )
{
data.vDummyfloat.push_back( static_cast< float >(i) );
data.vDummyint.push_back( static_cast< int >(i) );
}
AddData adddata;
TEST_BUFFER_TYPE buffer;
SerializeObjectHelper( data, buffer );
SerializeObjectHelper( adddata, buffer );
std::size_t size = sizeof(float);
TestDataDerived data2;
DeserializeObjectHelper( data2, &buffer[0], buffer.size() );
}
Boost Thread 샘플 & Lock-Free Queue 성능 테스트 (0) | 2016.01.31 |
---|---|
Boost Signals 샘플 (0) | 2016.01.31 |
Boost Serialization 샘플 (0) | 2016.01.31 |
Boost Regex 실전 사용 샘플 (0) | 2016.01.31 |
Boost Regex(정규식) 샘플 (0) | 2016.01.31 |
Boost 1.55 버전 기준으로 작성했습니다.
#include <boost/asio.hpp>
#include <iostream>
#include <string>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/map.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/scoped_ptr.hpp>
#include <boost/scoped_ptr.hpp>
class ANS_LOGIN
{
public:
// 로그인 성공
BOOL isOK;
// 사용자 식별번호
UINT uiUserSerialNumber;
// 사용자 이름
std::string strName;
// 경험치
LONG lExp;
// 레벨
UINT uiLevel;
// 소유 장비
std::map< LONG, LONG > mapEquipment;
// 친구목록
std::vector< UINT > vtGuildFriends;
private:
friend class boost::serialization::access;
template< class Archive >
void serialization( Archive& ar, const unsigned int version )
{
ar & isOK;
ar & strName;
ar & lExp;
ar & uiLevel;
ar & mapEquipment;
ar & vtGuildFriends;
}
};
template< typename T, typename Handler >
void async_write( const T& t, Handler hanldler )
{
//
std::ostringstream archive_stream;
boost::archive::text_oarchive archive( archive_stream );
archive << t;
std::string outboud_data_ = archive_stream.str();
// 헤더 초기화
std::ostringstream header_stream;
//header_stream << std::setw( header_length)
}
std::stringstream ss;
void save()
{
boost::archive::text_oarchive oa(ss);
int i = 1;
oa << i;
}
void load()
{
boost::archive::text_iarchive ia(ss);
std::cout << ss << std::endl;
int i = 0;
ia >> i;
std::cout << i << std::endl;
}
namespace Person_Test
{
std::stringstream ss;
class person
{
private:
int m_nAge;
std::string m_strName;
public:
person() {}
person( int _age, const std::string& _name ) : m_nAge( _age ), m_strName( _name ) {}
int age() const { return m_nAge; }
const std::string name() const { return m_strName; }
private:
friend class boost::serialization::access;
template< typename Archive >
void serialize( Archive& ar, const unsigned int version )
{
ar & m_nAge;
ar & m_strName;
}
};
class developer : public person
{
private:
std::string m_strLanguage;
public:
developer()
{
}
developer( int _age, const std::string& _name, const std::string& _language )
: person( _age, _name ), m_strLanguage( _language )
{
}
const std::string& language() const { return m_strLanguage; }
private:
friend class boost::serialization::access;
template< typename Archive >
void serialize( Archive& ar, const unsigned int version )
{
ar & boost::serialization::base_object<person>(*this);
ar & m_strLanguage;
}
};
/*template< typename Archive >
void serialize( Archive& ar, person& p, const unsigned int version )
{
ar & p.m_nAge;
ar & p.m_strName;
}*/
void save()
{
#define header_length 8
// 4바이트, 6바이트? 5바이트?
person* p = new person( 31, "boris" );
// Serialize the data first so we know how large it is.
std::ostringstream archive_stream;
boost::archive::binary_oarchive archive(archive_stream);
archive << p;
std::string outbound_data_ = archive_stream.str();
std::size_t size = outbound_data_.size();
// Format the header.
std::ostringstream header_stream;
header_stream << std::setw(header_length)
<< std::hex << outbound_data_.size();
if (!header_stream || header_stream.str().size() != header_length)
{
// Something went wrong, inform the caller.
//boost::system::error_code error(boost::asio::error::invalid_argument);
//socket_.get_io_service().post(boost::bind(handler, error));
return;
}
std::string outbound_header_ = header_stream.str();
// Write the serialized data to the socket. We use "gather-write" to send
// both the header and the data in a single write operation.
std::vector<boost::asio::const_buffer> buffers;
buffers.push_back(boost::asio::buffer(outbound_header_));
buffers.push_back(boost::asio::buffer(outbound_data_));
//boost::asio::async_write(socket_, buffers, handler);
//boost::asio::streambuf b;
//std::ostream os(&b);
////boost::archive::text_oarchive oa(ss);
////boost::scoped_ptr<developer> p( new developer( 31, "Boris", "C++" ) );
//person* p = new developer(31, "boris", "c++" );
////int i = 1;
//os << p;
///*os << i;
//os << i;
//os << i;
//os << i;
//os << "hello";
//os << 1.f;*/
//delete p;
//boost::asio::streambuf::const_buffers_type bufs = b.data();
//std::size_t n = b.size();
//b.consume( n );
}
void load()
{
boost::archive::text_iarchive ia(ss);
//boost::scoped_ptr<developer> p;
person* p;
ia >> p;
std::cout << p->age() << std::endl;
std::cout << p->name() << std::endl;
//std::cout << p->language() << std::endl;
delete p;
}
};
void serialization_test()
{
//Person_Test::save();
//Person_Test::load();
//Person_Test::main();
}
Boost Signals 샘플 (0) | 2016.01.31 |
---|---|
Boost Serializtion 샘플2 (0) | 2016.01.31 |
Boost Regex 실전 사용 샘플 (0) | 2016.01.31 |
Boost Regex(정규식) 샘플 (0) | 2016.01.31 |
Boost Random 샘플 (0) | 2016.01.31 |
Boost 1.55 버전 기준으로 작성했습니다.
- 업무중 큰 문제가 생겨 수만개의 로그를 분석해야 할 일이 생겨 사용해봤음
사실 문법이 조금 어렵고 까다로운데 잘 사용하면 정말 좋다.
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <boost/regex.hpp>
#include <boost/assign.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/foreach.hpp>
using namespace boost::assign;
const int BUFSIZE=100000;
typedef boost::tuple< std::string, int, int > problem_gameno;
typedef boost::tuple< std::string, int > checked_gameno;
bool Get_MatchesLine( std::ifstream& _in, std::vector< std::string >& _out_matches )
{
boost::regex re("(OnHoleStart)|(RecvGameNo)|(TPGameEnd,GameEnd)|(KRGL_Pay)");
char buf[BUFSIZE];
// 1차로 문자열로 걸러낸다.
while( !_in.eof() )
{
_in.getline(buf, BUFSIZE-1);
if( boost::regex_search( buf, re ) )
{
_out_matches += buf;
//std::cout << buf << std::endl;
}
}
return !_out_matches.empty();
}
void Get_MatchesProblemGame( const std::string& _file, std::vector< problem_gameno >& _problem_games, std::vector< checked_gameno >& _checked_games )
{
std::ifstream in(_file.c_str());
std::vector< std::string > matches;
if( Get_MatchesLine( in, matches ) )
{
std::cout << _file << "matches complete." << std::endl;
std::cout << std::endl;
boost::regex re("(OnHoleStart\\(\\)\\s*HoleGameNumber\\s*=\\s*)(3|12)");
boost::regex prevRe("(RecvGameNo\\s*ID\\s*=)(\\s*\\[(\\d+)\\])");
std::string::const_iterator begin;
boost::cmatch parse_match;
boost::cmatch prev_parse_match;
std::string prevMatche = "";
BOOST_FOREACH( std::string& _iter, matches )
{
begin = _iter.begin();
if( boost::regex_search( _iter.c_str(), parse_match, re ) )
{
//std::cout << "Prev : " << prevMatche << std::endl;
//std::cout << _iter << std::endl;
/*for( int i = 0; i < parse_match.size(); i++ )
{
std::string match( parse_match[i].first, parse_match[i].second );
std::cout << "\tmatches[" << i << "]" << match << std::endl;
}*/
//std::cout << std::endl;
std::string matchNumber( parse_match[2].first, parse_match[2].second );
int nMatchNum = boost::lexical_cast< int >( matchNumber );
if( boost::regex_search( prevMatche.c_str(), prev_parse_match, prevRe ) )
{
/*for( int i = 0; i < prev_parse_match.size(); i++ )
{
std::string match( prev_parse_match[i].first, prev_parse_match[i].second );
std::cout << "\tprev_matches[" << i << "]" << match << std::endl;
}*/
std::string gameNumber( prev_parse_match[3].first, prev_parse_match[3].second );
int nGameNum = boost::lexical_cast< int >( gameNumber );
std::cout << std::endl;
problem_gameno tu = boost::make_tuple( _file, nGameNum, nMatchNum );
_problem_games += tu;
//std::cout << tu << std::endl;
}
}
if( boost::regex_search( _iter.c_str(), parse_match, prevRe ) )
{
std::string gameNumber( parse_match[3].first, parse_match[3].second );
int nGameNum = boost::lexical_cast< int >( gameNumber );
checked_gameno tu = boost::make_tuple( _file, nGameNum );
_checked_games += tu;
}
prevMatche = _iter;
}
}
//getchar();
}
void Reallog_Analysis()
{
namespace fs = boost::filesystem;
std::vector< problem_gameno > problem_games;
std::vector< checked_gameno > checked_games;
std::string logPath = "RealLog\\";
fs::path full_path( fs::initial_path< fs::path >() );
full_path = fs::system_complete( fs::path( logPath ) );
if( !fs::exists( full_path ) )
{
std::cout << " Not Found" << full_path.c_str() << std::endl;
return;
}
if( fs::is_directory( full_path ) )
{
//std::cout << "\nIn directory: " << full_path.c_str() << "\n\n";
//fs::directory_iterator end_iter;
//for( fs::directory_iterator dir_itr( full_path ); dir_itr != end_iter; ++dir_itr)
//{
//}
//std::for_each( fs::directory_iterator(full_path), fs::directory_iterator(), boost::bind( Get_MatchesProblemGame, _1, problem_games ) );
//fs.directory_entry
typedef std::vector< fs::path > vec;
vec v;
std::copy( fs::directory_iterator(full_path), fs::directory_iterator(), back_inserter(v) );
std::sort( v.begin(), v.end() );
for( vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it )
{
//std::cout << " " << *it << std::endl
Get_MatchesProblemGame( (*it).string() , problem_games, checked_games );
}
}
//std::ifstream in(_file.c_str());
{
std::ofstream file("BillingMissList.txt");
BOOST_FOREACH( problem_gameno& _iter, problem_games )
{
file << _iter.get<0>();
file << "\t" << _iter.get<1>();
file << "\t" << _iter.get<2>() << std::endl;
}
}
{
std::ofstream file("CheckedList.txt");
BOOST_FOREACH( checked_gameno& _iter, checked_games )
{
//file << _iter.get<0>();
file << _iter.get<1>() << std::endl;
}
}
//std::string file( "RealLog\\Real_Log_2013_11_01_12_13_29.log" );
//Get_MatchesProblemGame( file, problem_games );
std::cout << "parse complete." << std::endl;
}
Boost Serializtion 샘플2 (0) | 2016.01.31 |
---|---|
Boost Serialization 샘플 (0) | 2016.01.31 |
Boost Regex(정규식) 샘플 (0) | 2016.01.31 |
Boost Random 샘플 (0) | 2016.01.31 |
Boost Pool 샘플 (0) | 2016.01.31 |
Boost 1.55 버전 기준으로 작성했습니다.
#include <iostream>
#include <string>
#include <boost/regex.hpp>
//
// boost:regex
// 정규식을 사용하기 위한 라이브러리
// 텍스트를 검색하고, 파싱하고, 문자열을 토큰으로 나누고, 검사하는 작업들을
// 정규화된 식을 통해서 간단하게 할 수 있도록 하는 그런 라이브러리
// 기호 의미
// c 특수문자가 아니라면 문자 c를 한 번 매치한다.
// ^ 줄의 시작을 매치한다.
// . 새 라인이 아닌 모든 문자를 매치한다.
// $ 줄의 끝을 매치한다.
// | 식들의 논리 OR
// () 그룹 표현
// [] 문자 클래스의 정의
// * 0번 또는 그 이상의 매치
// + 1번 또는 그 이상의 매치
// ? 0번 또는 1번 매치
// {n} 표현식을 n번 매치
// {n,} 표현식을 최소한 n번 매치
// {n,m} 최소 n번에서 최대 m번 까지 매치하는 식
// \d 숫자
// \D 숫자를 제외한 문자
// \w _를 포함한 알파벳 문자
// \W 알파벳이 아닌 문자
// \s 공백 문자(\t, \n, \r, \f)
// \S 공백 문자가 아닌 것
// \t 탭
// \n 새 라인
// \r 캐리지 리턴
// \f 폼 피드( Form Feed )
// \m 메타 문자( ^ . $ | () [] * + ? \ or / )들을 이스케이프
// 이것으로 무엇을 할수 있을까 한국의 주민번호에 해당하는 숫자를 문자열에서 검색 또는 매칭 할 수 있다.
// 간단한 정규식 \d{6}\-\d{7} 으로 매치할 수 있다.
// -는 정규식에서 메타문자로 사용하기 때문에 \을 붙여서 -(하이픈)를 찾는다.
//
// 간단하게 표현식을 테스트 할 수 있다.
void Regex_Simple_Test()
{
std::string s, sre;
boost::regex re;
while(true)
{
cout << "표현식 : ";
cin >> sre;
if( sre == "quit" )
{
break;
}
cout << "String: ";
cin >> s;
try
{
// 정규식 셋업
re.assign( sre, boost::regex_constants::icase );
}
catch (boost::regex_error& e)
{
std::cout << sre << " 은 유효하지 않은 표현식입니다:\"" << e.what() << "\"" << std::endl;
continue;
}
if( boost::regex_match( s, re ) )
{
std::cout << re << " 매치됨 " << s << std::endl;
}
else
{
std::cout << " 매치 실패 " << s << std::endl;
}
}
}
// 인터넷 주소창 검색 예제
void Regex_URL_Match_Test()
{
std::string url = "ftp://downloads.foo.com/apps/linux/patch.gz";
boost::regex re( "(ftp|http|https)://(\w+\.)*(\w*)\/([\w\d]+\/{0,1})+");
try
{
if( !boost::regex_match( url, re ) )
{
throw "Your URL is not formatted correctly!";
}
}
catch( boost::regex_error& e )
{
cerr << "Tex regexp " << re << " is invalid!" << std::endl;
throw(e);
}
}
//
// regex serach 테스트
void Regex_Search_Test()
{
const char* source = "abc1234def";
// [a-zA-Z] = a~z 또는 A~Z 까지의 문자
// .* = 새 라인이 모든문자가 0번 또는 그 이상
// // [a-zA-Z] = a~z 또는 A~Z 까지의 문자
//boost:reg_expression<char> regex = "([a-zA-Z](.*)[a-zA-Z]";
boost::regex regex( "([a-zA-Z])(.*)[a-zA-Z]" );
boost::match_results< const char* > results;
if( boost::regex_search( source, results, regex ) )
{
std::cout << results.str( 1 ) << std::endl;
}
}
Boost Serialization 샘플 (0) | 2016.01.31 |
---|---|
Boost Regex 실전 사용 샘플 (0) | 2016.01.31 |
Boost Random 샘플 (0) | 2016.01.31 |
Boost Pool 샘플 (0) | 2016.01.31 |
Boost Optional 샘플 (0) | 2016.01.31 |
Boost 1.55 버전 기준으로 작성했습니다.
#pragma once
//================================================================
/**
@author skhong
@since 7/7/2014 17:16
@remarks 주사위를 굴리자
*/
//================================================================
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random/uniform_real_distribution.hpp>
#include <boost/random/discrete_distribution.hpp>
#include "Singleton.h"
// 주사위 굴리기
struct RollDie
{
inline
int operator()( int _LowerBound = 0, int nUpperBound = 32767 )
{
static boost::mt19937 gen;
static BOOL init = FALSE;
if( !init )
{
gen.seed(std::time(0));
init = TRUE;
}
boost::random::uniform_int_distribution<> dist( _LowerBound, nUpperBound );
return dist(gen);
}
};
// 주사위 굴리기
struct fRollDie
{
inline
double operator()( double _LowerBound = 0.f, double nUpperBound = 32767.f )
{
static boost::mt19937 gen;
static BOOL init = FALSE;
if( !init )
{
gen.seed(std::time(0));
init = TRUE;
}
boost::random::uniform_real_distribution<> dist( _LowerBound, nUpperBound );
return dist(gen);
}
};
//
// 가중치를 가지는 주사위 굴리기
// 가중치는 1.0f
// 넘오는 가중치는 합이 1.0f을 넘지 않도록 한다.
struct RollWeightedDie
{
inline
int operator()( std::vector<double> const& _Probabilities )
{
static boost::mt19937 gen;
static BOOL init = FALSE;
if( !init )
{
gen.seed(std::time(0));
init = TRUE;
}
boost::random::discrete_distribution<> dist( _Probabilities );
return dist(gen);
}
};
Boost Regex 실전 사용 샘플 (0) | 2016.01.31 |
---|---|
Boost Regex(정규식) 샘플 (0) | 2016.01.31 |
Boost Pool 샘플 (0) | 2016.01.31 |
Boost Optional 샘플 (0) | 2016.01.31 |
Multi Index 샘플 (0) | 2016.01.31 |
Boost 1.55 버전 기준으로 작성했습니다.
#include <iostream>
#include <string>
#include <vector>
#include <boost/pool/pool.hpp>
#include <boost/pool/object_pool.hpp>
#include <boost/pool/singleton_pool.hpp>
#include <boost/pool/pool_alloc.hpp>
#include <boost/timer.hpp>
#include <boost/progress.hpp>
//
// boost::pool
// 고정 크기의 블럭(chunk)들을 할당할때 고속으로 작동
// 메모리 사용시 속도와 단편화 문제를 해결하기 위해서 사용함
// 할당 범위 초과시 2배씩 Grow
// 객체가 소멸될때 자동으로 메모리 해제
class MyClass
{
std::string m_name;
int m_num;
public:
MyClass( const std::string& _name ) : m_name( _name )
{
static int num = 0;
std::cout << "MyClass Constructor : " << ( m_num = ++num ) << std::endl;
}
~MyClass()
{
std::cout << "MyClass Destructor : " << m_num << std::endl;
}
void Print() { std::cout << m_name << " : Print() Call " << std::endl; }
};
struct MyPoolTag{};
void Pool_Test()
{
// 기본 데이터형 메모리 풀
{
// int 형 메모리 풀
boost::pool<> p( sizeof(int) );
int* x = static_cast< int* >(p.malloc());
int* y = static_cast< int* >(p.malloc());
int* z = static_cast< int* >(p.malloc());
*x = 10;
p.free( z );
// free 를 하지 않아도 pool 객체가 소멸과 동시에 알아서 해제됨
}
// 오브젝트 메모리 풀
{
boost::object_pool< MyClass > p;
MyClass* const x = p.construct( "VANICA_X" );
MyClass* const y = p.construct( "VANICA_Y" );
MyClass* z = p.construct( "VANICA_Y" );
y->Print();
p.destroy(y);
}
// 스레드에 안전한 싱글톤 메모리 풀
{
typedef boost::singleton_pool
<
MyPoolTag, // 태그
sizeof( int ), // 풀 사이즈
boost::default_user_allocator_new_delete, // 메모리 할당자는 기본
boost::details::pool::default_mutex, // 기본적으로 뮤텍스를 사용하여 스레드 동기화
18 // 최대 사용 메모리
> my_pools;
for( int i = 0; i < 18; ++i )
{
int* const myInt = static_cast< int* >( my_pools::malloc() );
*myInt = i;
std::cout<< "my int : " << *myInt << std::endl;
}
// 할당받은 모든 int 들은 무조건 이곳에서 해제됨
my_pools::purge_memory();
}
// 스레드에 안전한 싱글톤 오브젝트 메모리 풀도 있냐?
{
//typedef boost::singleton_pool< , sizeof( MyClass ) > my_object_pools;
//MyClass* const pMy = my_object_pools::malloc();
}
}
// 간단한 실제 사용되는 메모리 풀
template< class T >
class BoostMemoryAllocT
{
public:
// operator new 재 정의
static void* operator new(std::size_t size )
{
// 스레드에 안전한 메모리 풀
//typedef boost::singleton_pool
//<
//T, sizeof(T),
//boost::default_user_allocator_new_delete, // 메모리 할당자는 기본
//boost::details::pool::default_mutex, // 기본적으로 뮤텍스를 사용하여 스레드 동기화
//> boost_mem_alloc;
return boost::singleton_pool< T, sizeof( T ) >::malloc();
}
// operator delete 재 정의
static void operator delete( void* p )
{
boost::singleton_pool< T, sizeof( T ) >::free(p);
}
};
class BoostPoolClass : public BoostMemoryAllocT< BoostPoolClass >
{
private:
char _dummy[MAX_PATH];
};
class BoostPoolClass2
{
private:
char _dummy[MAX_PATH];
};
template< class T >
void MemoryActionType1( const std::string& _allocatorName, int iterationCount )
{
// 프로그레스 타이머
boost::progress_timer progress_t;
boost::progress_display show_progress( iterationCount );
for( int i = 0; i < iterationCount; ++i )
{
T* p = new T();
assert( NULL != p );
delete p;
++show_progress;
}
std::cout << "allocator name : " << _allocatorName << std::endl;
}
template< class T >
void MemoryActionType2( const std::string& _allocatorName, int iterationCount )
{
// 부스트 프로그레스들 상세 사용법은 알아서 찾으셈
// 소멸자에서 걸린 시간을 표시함
boost::progress_timer progress_t;
// 프로그레스바를 표시함
boost::progress_display show_progress( iterationCount * 2 );
std::vector< T* > container;
for( int i = 0; i < iterationCount; ++i )
{
T* p = new T();
assert( NULL != p );
container.push_back( p );
++show_progress;
}
// 부스트 foreach 문
BOOST_FOREACH( T* iter, container )
{
delete iter;
++show_progress;
}
std::cout << "allocator name : " << _allocatorName << std::endl;
}
void BoostMemoryAllocator_Test()
{
const int allocCount = 3000000;
std::cout << "메모리 할당, 해제 함께 " << allocCount << std::endl;
MemoryActionType1<BoostPoolClass>( "부스트 메모리 풀__", allocCount );
std::cout << "메모리 할당, 해제 따로 " << allocCount << std::endl;
MemoryActionType2<BoostPoolClass>( "부스트 메모리 풀__", allocCount );
std::cout << "메모리 할당, 해제 함께 " << allocCount << std::endl;
MemoryActionType1<BoostPoolClass2>( "기본 메모리__", allocCount );
std::cout << "메모리 할당, 해제 따로 " << allocCount << std::endl;
MemoryActionType2<BoostPoolClass2>( "기본 메모리__", allocCount );
std::cout << "부스트 메모리 풀과 일반 메모리 할당 테스트 끝!!" << std::endl;
}
Boost Regex(정규식) 샘플 (0) | 2016.01.31 |
---|---|
Boost Random 샘플 (0) | 2016.01.31 |
Boost Optional 샘플 (0) | 2016.01.31 |
Multi Index 샘플 (0) | 2016.01.31 |
Boost MPL 샘플 (0) | 2016.01.29 |
Boost 1.55 버전 기준으로 작성했습니다.
#include <iostream>
#include <string>
#include <boost/optional.hpp>
//
// boost::optional
// 값(value)을 리턴 하는 함수에서 유효하지 않은 값을 리턴하기 위해서 enum 또는 define을 사용해
// 유효하지 않은 값을 정의해야 하는데 이게 비효율적으로 늘어나고 코딩하기 귀찮고 관리하기도 힘들기 때문에
// 아주 간단하게 유효하지 않은 값을 리턴할 수 있도록 만들어졌음
optional< std::string > find_username( int _userid )
{
// 잘못된 값
if( _userid == 0 )
return optional< std::string >();
// 이런식으로 찾은 후
bool bFind = true;//find_user();
if( bFind == false )
return optional< std::string >();
return optional< std::string >( "skhong" );
}
void Optional_Test()
{
// 유저를 찾음
optional< std::string > username = find_username( 10 );
if( username )
std::cout << "유저 이름 : " << *username << std::endl;
else
std::cout << "유저를 찾지 못했어요" << std::endl;
// 잘못된 아이디를 던짐
username = find_username( 0 );
if( username )
std::cout << "유저 이름 : " << *username << std::endl;
else
std::cout << "유저를 찾지 못했어요" << std::endl;
}
Boost Random 샘플 (0) | 2016.01.31 |
---|---|
Boost Pool 샘플 (0) | 2016.01.31 |
Multi Index 샘플 (0) | 2016.01.31 |
Boost MPL 샘플 (0) | 2016.01.29 |
Boost Meta State Machine 테스트 2 (0) | 2016.01.29 |
Boost 1.55 버전 기준으로 작성했습니다.
#pragma once
#include <iostream>
#include <string>
// multi index
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <iostream>
#include <string>
// 클라스
class CPlayer
{
public:
int _ID;
std::string _Name;
//bool _Sex;
int getID() const { return _ID; }
std::string getName() const { return _Name; }
bool getSex() const
{
if( _Name == "test" )
return false;
return true;
}
void setID( int id ) { _ID = id; }
void setName( std::string const& name ) { _Name = name; }
//void setSex( bool sex ) { _Sex = sex; }
CPlayer( int id, std::string name ) : _ID( id ), _Name( name ) {}
};
// 태그들
struct tagID {};
struct tagName {};
struct tagBoth {};
struct tagSex {};
// 멀티 인덱스 container
typedef boost::multi_index::multi_index_container
<
CPlayer,
boost::multi_index::indexed_by
<
// 첫번째 키
boost::multi_index::ordered_non_unique
<
boost::multi_index::tag< tagID >, boost::multi_index::const_mem_fun< CPlayer, int, &CPlayer::getID >
>,
// 두번째 키
boost::multi_index::hashed_non_unique
<
boost::multi_index::tag< tagName >, boost::multi_index::const_mem_fun< CPlayer, std::string, &CPlayer::getName >
>,
// 세번째 조합 키( hole numer 와 player name )
boost::multi_index::ordered_non_unique
<
boost::multi_index::tag< tagBoth >, boost::multi_index::composite_key< CPlayer,
boost::multi_index::const_mem_fun< CPlayer, int, &CPlayer::getID >,
boost::multi_index::const_mem_fun< CPlayer, std::string, &CPlayer::getName >,
boost::multi_index::const_mem_fun< CPlayer, bool, &CPlayer::getSex >
>
>,
// 네번째 키
boost::multi_index::hashed_non_unique
<
boost::multi_index::tag< tagSex >, boost::multi_index::const_mem_fun< CPlayer, bool, &CPlayer::getSex >
>
>
> TurnMultiindex;
typedef TurnMultiindex::index< tagID >::type IDIndex;
typedef TurnMultiindex::index< tagName >::type NameIndex;
typedef TurnMultiindex::index< tagBoth >::type BothIndex;
typedef TurnMultiindex::index< tagSex >::type SexIndex;
std::ostream& operator << ( std::ostream& rOut, CPlayer const& rPlayer )
{
return rOut << rPlayer.getID() << " / " << rPlayer.getName() << " / " << std::boolalpha << rPlayer.getSex() << std::endl;
}
void set( CPlayer& p )
{
p.setID( 10 );
p.setName( "test" );
//p.setSex( false );
}
void multi_index_test()
{
TurnMultiindex players;
players.insert( CPlayer( 0, "skhong" ) );
players.insert( CPlayer( 0, "skhong" ) );
players.insert( CPlayer( 0, "skhong" ) );
players.insert( CPlayer( 0, "skhong" ) );
/*players.insert( CPlayer( 2, "okidoki" ) );
players.insert( CPlayer( 3, "skhong" ) );
players.insert( CPlayer( 1, "woowoo" ) );
players.insert( CPlayer( 5, "Nok" ) );
players.insert( CPlayer( 0, "filco" ) );*/
//TurnMultiindex::iterator it = players.find( 0 );
//players.modify( it, set );
// id로 검색
std::cout << "find ID" << std::endl;
IDIndex::const_iterator itIDLower;
IDIndex::const_iterator itIDUpper;
boost::tie( itIDLower, itIDUpper ) = players.get< tagID >().equal_range( 0 );
std::copy( itIDLower, itIDUpper, std::ostream_iterator< CPlayer >( std::cout << "\n" ) );
//players.get< tagID >().modify( itIDLower, set );
// 이름으로 검색
std::cout << "find Name" << std::endl;
NameIndex::const_iterator itNameLower;
NameIndex::const_iterator itNameUpper;
boost::tie( itNameLower, itNameUpper ) = players.get< tagName >().equal_range( "test" );
std::copy( itNameLower, itNameUpper, std::ostream_iterator< CPlayer >( std::cout << "\n" ) );
//players.get< tagID >().modify( itIDLower, set );
//// id 와 이름으로 검색
std::cout << "find All" << std::endl;
BothIndex::const_iterator itBothLower;
BothIndex::const_iterator itBothUpper;
boost::tie( itBothLower, itBothUpper ) = players.get< tagBoth >().equal_range( boost::make_tuple( 0, "skhong", true ) );
std::copy( itBothLower, itBothUpper, std::ostream_iterator< CPlayer >( std::cout << "\n" ) );
boost::tie( itBothLower, itBothUpper ) = players.get< tagBoth >().equal_range( boost::make_tuple( 10, "test", false ) );
std::copy( itBothLower, itBothUpper, std::ostream_iterator< CPlayer >( std::cout << "\n" ) );
BothIndex::const_iterator itBothF = players.get< tagBoth >().find( boost::make_tuple( 0, "skhong", true ) );
//std::copy( itBothLower, itBothUpper, std::ostream_iterator< CPlayer >( std::cout << "\n" ) );
//// id 와 이름으로 검색
std::cout << "find sex" << std::endl;
SexIndex::const_iterator itSexLower;
SexIndex::const_iterator itSexUpper;
boost::tie( itSexLower, itSexUpper ) = players.get< tagSex >().equal_range( true );
std::copy( itSexLower, itSexUpper, std::ostream_iterator< CPlayer >( std::cout << "\n" ) );
boost::tie( itSexLower, itSexUpper ) = players.get< tagSex >().equal_range( false );
std::copy( itSexLower, itSexUpper, std::ostream_iterator< CPlayer >( std::cout << "\n" ) );
//// 순차적인거
//SquencedIndex::const_iterator itSquenceLower;
//SquencedIndex::const_iterator itSquenceUpper;
//SquencedIndex& squenceIndex = players.get< tagSquenced >();
//boost::tie( itSquenceLower, itSquenceUpper ) = players.get< tagSquenced >().equal_range( 0, 3 );
//std::copy( itSquenceLower, itSquenceUpper, std::ostream_iterator< CPlayer >( std::cout << "\n" ) );
}
Boost Pool 샘플 (0) | 2016.01.31 |
---|---|
Boost Optional 샘플 (0) | 2016.01.31 |
Boost MPL 샘플 (0) | 2016.01.29 |
Boost Meta State Machine 테스트 2 (0) | 2016.01.29 |
Boost Meta State Machine 테스트 (0) | 2016.01.29 |