'Programming/C++'에 해당되는 글 2건

  1. 2008.07.26 Command Pattern - 일반화 구현 by 1stPasa
  2. 2008.05.25 MersenneTwister - Advanced 난수발생기 by 1stPasa

커맨드 패턴을 Function 과 Method 에 대해 일반화 하고

인수타입과 리턴타입에 대해서도 일반화 하였다.

한글이름도 어려운 명시적 템플릿 구체화까지 써가면서도

인수타입이 void 인경우에 대해 NoArg란 이름을 붙여 따로 정의할수밖에 없었던 이유는

생각지 못했던 Ambigious 문제가 발생했기 때문이다. ( 겪고보니 당연한 일이었지만.. )

결국 클래스의 종류는

Command ( 상위 클래스 )
MethodCommand, MethodCommandNoArg
FunctionCommand, FunctionCommandNoArg

다섯가지나 된다.. 사용할때 올바른 인스턴스를 만들어주는게 번거로우므로

MakeCommand 란 함수를 만들었는데 이것역시 템플릿 함수임에도 불구하고 4가지 버전이나 된다.

그놈의 void가 문제지.. return type 으로도 안되고 Argument로 넣을수도 없으니 별도로 구체화 시킬수밖에..ㅋ

아래는 그렇게 구현한 Command 패턴들과 MakeCommand 코드이다.

#pragma once
template <typename _A, typename _R>
class Command
{
public:
 virtual _R Fire(_A) = 0;
};

template<typename _T, typename _A, typename _R>
class MethodCommand : public Command<_A,_R>
{
 _T *m_obj;
 _R (_T::*m_mf)(_A);
public:
 MethodCommand(_T * object, _R (_T::*method)(_A)) : m_obj(object), m_mf(method) {}
 virtual inline _R Fire(_A arg){ return (m_obj->*m_mf)(arg);}
};

template<typename _T, typename _A>
class MethodCommand<_T,_A,void> : public Command<_A,void>
{
 _T *m_obj;
 void (_T::*m_mf)(_A);
public:
 MethodCommand(_T * object, void (_T::*method)(_A)) : m_obj(object), m_mf(method) {}
 virtual inline void Fire(_A arg){(m_obj->*m_mf)(arg);}
};

template <typename _T, typename _R>
class MethodCommandNoArg : public Command<void,_R>
{
 _T *m_obj;
 _R (_T::*m_mf)();
public:
 MethodCommandNoArg(_T * object, _R (_T::*method)()) : m_obj(object), m_mf(method) {}
 virtual inline _R Fire(void){ return (m_obj->*m_mf)();}
};

template <typename _T>
class MethodCommandNoArg<_T,void> : public Command<void,void>
{
 _T *m_obj;
 void (_T::*m_mf)();
public:
 MethodCommandNoArg(_T * object, void (_T::*method)()) : m_obj(object), m_mf(method) {}
 virtual inline void Fire(void){ (m_obj->*m_mf)();}
};

template <typename _A,typename _R>
class FunctionCommand : public Command<_A,_R>
{
 _R (*m_mf)(_A);
public:
 FunctionCommand(_R (*func)(_A)) : m_mf(func){}
 virtual inline _R Fire(_A arg){ return (*m_mf)(arg); }
};

template <typename _A>
class FunctionCommand<_A,void> : public Command<_A,void>
{
 void (*m_mf)(_A);
public:
 FunctionCommand(void (*func)(_A)) : m_mf(func){}
 virtual inline void Fire(_A arg){ (*m_mf)(arg); }
};

template <typename _R>
class FunctionCommandNoArg : public Command<void,_R>
{
 _R (*m_mf)(void);
public:
 FunctionCommandNoArg(_R (*func)(void)) : m_mf(func){}
 virtual inline _R Fire(void){ return (*m_mf)(); }
};

template <>
class FunctionCommandNoArg<void> : public Command<void,void>
{
 void (*m_mf)(void);
public:
 FunctionCommandNoArg(void (*func)(void) ) : m_mf(func){}
 virtual inline void Fire(void){ (*m_mf)(); }
};

template <typename _T, typename _A, typename _R>
Command<_A,_R>* MakeCommand( _T *target, _R (_T::*method)(_A) )
{
 return new MethodCommand<_T,_A,_R>( target, method );
}

template <typename _T, typename _R>
Command<void,_R>* MakeCommand( _T *target,  _R (_T::*method)(void) )
{
 return new MethodCommandNoArg<_T,_R>( target, method );
}

template <typename _A, typename _R>
Command<_A,_R>* MakeCommand( _R (*function)(_A) )
{
 return new FunctionCommand<_A,_R>( function );
}

template < typename _R>
Command<void,_R>* MakeCommand(_R (*function)(void) )
{
 return new FunctionCommandNoArg<_R>( function );
}

Command<_A , _R>  
-  _A : 인수 타입
-  _R : 반환 타입

간단하게 시작했는데 100줄을 넘겨버렸다.. ㅎㅎ

아래는 예제코드로서

void 와 void가 아닌 타입들을 대입할수 있다고 생각하면 되겠다.

위에서 말한것과 같이 void 의 경우 return 타입으로 쓸수 없기 때문에

return func1(); 과 같은 형태로 사용할수도 없고.

func1( arg ); 와 같은형태로 인수로 넣을수도 없다.

#include "Command.h"
#include <iostream>
using namespace std;

class MyClass
{
public:
 void method1()
 {
  cout << "void Method(void)" << endl;
 }

 int method2(int a)
 {
  cout << "int Method(int)" << endl;
  return a;
 }

 int method3(void* a)
 {
  cout << "int Method(void*)" << endl;
  return 10;
 }

 void method4(int a)
 {
  cout << "void Method(int)" << endl;
 }
};

void func1()
{
 cout << "void function(void)" << endl;
}

int func2(int a)
{
 cout << "int function(int)" << endl;
 return a;
}

int func3(void* a)
{
 cout << "int function(void*)" << endl;
 return 10;
}

void func4(int a)
{
 cout << "void function(int)" << endl;
}


int main(int argc, char* argv[])
{
 MyClass a;

 Command<void,void> *m1 = MakeCommand(&a, &MyClass::method1 );
 Command<int,int> *m2 = MakeCommand(&a, &MyClass::method2 );
 Command<void*,int> *m3 = MakeCommand(&a, &MyClass::method3 );
 Command<int,void> *m4 = MakeCommand(&a, &MyClass::method4 );
 
 Command<void,void> *f1 = MakeCommand(func1);
 Command<int,int> *f2 = MakeCommand(func2);
 Command<void*,int> *f3 = MakeCommand(func3);
 Command<int,void> *f4 = MakeCommand(func4);
 
 m1->Fire();
 m2->Fire(10);
 m3->Fire(NULL);
 m4->Fire(10);

 f1->Fire();
 f2->Fire(10);
 f3->Fire(NULL);
 f4->Fire(10);

 return 0;
}

생각같아선 C#의 델리게이트처럼 인수의 갯수도 일반화 시켜버리고 싶지만..

아무리 생각해도 인라인어셈을 동원하지 않고는 구현이 불가능한것 같다.

그렇게되면 컴파일타임 에러체크가 안되므로 패스하고

결국 이쯤에서 마무리를 짓는것이 좋을듯.
Posted by 1stPasa

댓글을 달아 주세요

Game Programming Gems 4권에 나오는 난수발생기 이다.

본문에 따르면 c의 rand 함수보다 빠르고 주기가 길다( 반복이 일어나기까지 2^19937 - 1 )

따라서 무작위성이 보장되고 아울러 64비트로의 확장도 용이하다

하물며 c의 rand 함수는 16비트밖에 안되기때문에

rand 함수보다는 훨씬 유용하다 할만하다.


코드상에 있는 무지막지한 배열은 seed 정도로 보면 되는데

저부분에 들어갈 값을 srand() + rand() 조합으로 넣어주면

더욱 훌륭한 난수발생기가 될수 있겠다.

아래의 코드는 MT 부분만 따온것.

클래스 생성하고 Rand() 혹은 Rand64() 함수만 호출하면 된다.

의외로 기능에 비해 동작 원리랄건 별것 없지만 자세한 내용은 책에..ㅋㅋ

#include <iostream>
#include <cassert>
// Specialized templates to compute powers of two at compile time
// (template metaprogramming)
template<int N>
struct Pow2
{
    enum { value = 2 * Pow2<N - 1>::value };
};
template<>
struct Pow2<0>
{
    enum { value = 1 };
};
template<int N>
struct Pow2Minus1
{
    enum { value = Pow2<N - 1>::value - 1 + Pow2<N - 1>::value };
};
// This is defined in C99, but not C++ yet (June 2003)
typedef unsigned long uint32_t;
#if defined(_WIN32)
typedef unsigned __int64 uint64_t;
#elif defined (__GNUC__)
typedef unsigned long long uint64_t;
#endif
// Parameters for MT19937
// See Matsumoto for definition of parameters, and
// alternate parameters for different k-distributions.
static const int      MT_W = 32;            // word size
static const int      MT_N = 624;           // degree of recursion
static const int      MT_M = 397;           // middle term
static const int      MT_R = 31;            // separation point of one word
static const uint32_t MT_A = 0x9908b0df;    // vector parameter a (matrix A)
static const int      MT_U = 11;            // integer parameter u
static const int      MT_S = 7;             // integer parameter s
static const uint32_t MT_B = 0x9d2c5680;    // vector parameter b
static const int      MT_T = 15;            // integer parameter t
static const uint32_t MT_C = 0xefc60000;    // vector parameter c
static const int      MT_L = 18;            // integer parameter l
// Autogenerate the masks based on the R parameter. All of the
// proposed MT parameters have a 32-bit word size, so I assume that.
static const uint32_t MT_LLMASK = Pow2Minus1<MT_R>::value;
static const uint32_t MT_UMASK  = 0xffffffff - Pow2Minus1<MT_R>::value;
// All values for the array are fine initial seed choices, except for
// an array of all zeros.
static uint32_t s_aMT[MT_N] = {
       2,    3,    5,    7,   11,   13,   17,   19,   23,   29,
      31,   37,   41,   43,   47,   53,   59,   61,   67,   71,
      73,   79,   83,   89,   97,  101,  103,  107,  109,  113,
     127,  131,  137,  139,  149,  151,  157,  163,  167,  173,
     179,  181,  191,  193,  197,  199,  211,  223,  227,  229,
     233,  239,  241,  251,  257,  263,  269,  271,  277,  281,
     283,  293,  307,  311,  313,  317,  331,  337,  347,  349,
     353,  359,  367,  373,  379,  383,  389,  397,  401,  409,
     419,  421,  431,  433,  439,  443,  449,  457,  461,  463,
     467,  479,  487,  491,  499,  503,  509,  521,  523,  541,
     547,  557,  563,  569,  571,  577,  587,  593,  599,  601,
     607,  613,  617,  619,  631,  641,  643,  647,  653,  659,
     661,  673,  677,  683,  691,  701,  709,  719,  727,  733,
     739,  743,  751,  757,  761,  769,  773,  787,  797,  809,
     811,  821,  823,  827,  829,  839,  853,  857,  859,  863,
     877,  881,  883,  887,  907,  911,  919,  929,  937,  941,
     947,  953,  967,  971,  977,  983,  991,  997, 1009, 1013,
    1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069,
    1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151,
    1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223,
    1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291,
    1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373,
    1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451,
    1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511,
    1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583,
    1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657,
    1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
    1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811,
    1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889,
    1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987,
    1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053,
    2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129,
    2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213,
    2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287,
    2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357,
    2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423,
    2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531,
    2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617,
    2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687,
    2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741,
    2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819,
    2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903,
    2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999,
    3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079,
    3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181,
    3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257,
    3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331,
    3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413,
    3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511,
    3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571,
    3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643,
    3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727,
    3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821,
    3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907,
    3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989,
    4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057,
    4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139,
    4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231,
    4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297,
    4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409,
    4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493,
    4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583,
    4591, 4597, 4603, 4621
};
class MersenneTwister
{
    int m_ix;     void Regenerate(); public:
    MersenneTwister();     uint32_t Rand();
    uint64_t Rand64();
};
void MersenneTwister::Regenerate()
{
    // NOTE: this should be unrolled in an optimized version
    // to eliminate the modulus operator.
    for(int kk = 0; kk < MT_N; kk++)
    {
        uint32_t ui = (s_aMT[kk] & MT_UMASK) | (s_aMT[(kk + 1) % MT_N] & MT_LLMASK);
        s_aMT[kk] = s_aMT[(kk + MT_M) % MT_N] ^ (ui >> 1) ^ ((ui & 0x00000001) ? MT_A : 0);
    }
}
MersenneTwister::MersenneTwister() :
    m_ix(0)
{
    // s_aMT is already initialized with the first N primes.
    Regenerate();
}
uint32_t MersenneTwister::Rand()
{
    if (m_ix == MT_N)
    {
        m_ix = 0;         Regenerate();
    }     uint32_t y;
    y = s_aMT[m_ix++];
    y ^= y >> MT_U;
    y ^= y << MT_S & MT_B;
    y ^= y << MT_T & MT_C;
    y ^= y >> MT_L;     return y;
}
uint64_t MersenneTwister::Rand64()
{
    uint64_t ui64;     ui64 = Rand();
    ui64 <<= 32;
    ui64 |= Rand();     return ui64;
}
Posted by 1stPasa

댓글을 달아 주세요