boost 관련 예제 프로그래밍..

가끔 경의롭단 생각이.. 이거 만든사람은 뇌에 cpu 박았나...

예전 모 회사 프로그래머가 신의 한수를 알려주겠다고 memcpy를 한번 짜보라고 하시더군요..

그래서 그냥 생각나는데요 조금 노멀하게...

 

void MyMemcpy(void *dest, void *src, size_t len){

char *dest8 = (char*)&dest;

char *src8 = (char*)&src;

 

while(--len){

*dest8++ = *src8++;

}

}

 

했는데, 이거 봐서 님의 경력은 얼마 안되네요 ㅋㅋ 하시더군요

ㅡ_ㅡ...

 

그래서 조금 고친것이

dest메모리 영역과 src메모리 영역이 겹치는지 확인하는 코드를 넣었습니다.

bool MyMemCpy(void *dest, void *src, size_t len)
{
    char *dest8 = (char*)dest;
    char *src8 = (char*)src;

    /////////////////////////////////
    //dest ■■■■■              //1.dest 메모리 영역안에 src가 있거나
    //        src □□□□□
    //            dest ■■■■■  //2.src 메모리 영역안에 dest가 있으면 안됨
    /////////////////////////////////

    if((dest8 <= src8 //1검사
       && src8 <= dest8+len)
    ||(src8 <= dest8 //2검사
       && dest8 <= src8+len))
    {
        return false;
    }

    while(len--){
        *dest8++ = *src8++;
    }

    return true;
}

 

뭐 여기까지 하면 그래도 안전하지 않냐라는 생각이 들었습니다만...

 

최근 boost 라이브러리(mpl 프로그래밍)쪽을 공부하면서 이런 방법이 나오더군요..

#include <typeinfo>
#include <algorithm>
#include <iterator>
#include <memory>

#include <boost/test/included/prg_exec_monitor.hpp>
#include <boost/timer.hpp>
#include <boost/type_traits.hpp>

 

//기존의 copy와 차별화를 위한 네임스페이스
namespace opt{
    namespace detail{
        //이건 직접 대입시켜서 복사하는 방식
        template<typename l1, typename l2, bool b>
        l2 copy_imp(l1 first, l1 last, l2 out, const boost::integral_constant<bool, b>&)
        {
           while(first != last){
                *out = *first;
                ++out;
                ++first;
            }
            return out;
        }

 

       //memcpy를 이용하는 방식
       template<typename T>
       T* copy_imp(const T *first, const T *last, const boost::true_type&)
       {
            memcpy(out, first, (last-first)*sizeof(T));
            return out+(last-first);
        }
    }

 

    //실제 copy명령어
    template <typename l1, typename l2>
    inline l2 copy(l1 first, l1 last, l2 out)
    {
          //복사하는것의 타입을 알아내서
          typedef typename std::iterator_traits<l1>::value_type value_type;

 

    //l1에대해서 "C& C::operator=(const C&);" 와 같은 정의가 없다면
    //trivial_assignment operator 를 가지게 됨. 

    //하지만 컴파일러 능력상 이걸 알아내는건 제각각임;;;
    return detail::copy_imp(first, last, out, boost::has_trivial_assign<value_type>());

    }

}

 

/////////////////////////////////////////////////////////////////////////////////////////////////////

// 이 밑은 위의 소스를 테스트 하는 소스

const int array_size = 1000;
int   i_array_[array_size] = {0,};
const int ci_array_[array_size] = {0,};
char  c_array_[array_size] = {0,};
const char cc_array_[array_size] = {0,};

int *i_array   = i_array_;
const int *ci_array  = ci_array_;
char *c_array   = c_array_;
const char *cc_array = cc_array_;

const int iter_count = 1000000;

 

using namespace std;

int cpp_main(int argc, char* argv[])
{
    boost::timer t;
    double result;
 
    cout << "Measuring times in micro-seconds per "<< array_size << " elements processed" << endl;
    cout << "Testing copy... " << endl;
    cout << "  [some standard liberay version may already perform this optimisation.]" << endl;
  
    //////////////////////////////////////////////////////////////////////////
    //cache load
    opt::copy(ci_array, ci_array + array_size, i_array);

    //time optimised verstion
    t.restart();
    for(int i=0; i< iter_count; ++i){
        opt::copy(ci_array, ci_array + array_size, i_array);
    }
    result = t.elapsed();
    cout << "opt::copy<const int*, int*> : " << result << endl;

 

    //////////////////////////////////////////////////////////////////////////
    //cache load;
    std::copy(ci_array, ci_array + array_size, i_array);

    //time standard version
    t.restart();
    for(int i=0; i< iter_count; ++i){
        std::copy(ci_array, ci_array + array_size, i_array);
    }
    result = t.elapsed();
    cout << "std::copy<const int*, int*> : " << result << endl;

  

    //////////////////////////////////////////////////////////////////////////
    //cache load
    opt::copy(cc_array, cc_array + array_size, c_array);

    //time optimised verstion
    t.restart();
    for(int i=0; i< iter_count; ++i){
        opt::copy(cc_array, cc_array + array_size, c_array);
     }
     result = t.elapsed();
     cout << "opt::copy<const char*, char*> : " << result << endl;

 

     //////////////////////////////////////////////////////////////////////////
     //cache load;
     std::copy(cc_array, cc_array + array_size, c_array);

     //time standard version
     t.restart();
     for(int i=0; i< iter_count; ++i){
         std::copy(cc_array, cc_array + array_size, c_array);
     }
     result = t.elapsed();
     cout << "std::copy<const char*, char*> : " << result << endl;

  

     return 0;
}

 

메타프로그래밍은 프로그램 소스를 프로그래밍 하는 개념인데...

위의 메모리 복사 예제 처럼 C++의 템플릿을 가지고, 컴파일러가 타입에 따라 가장 적절한 알고리즘을 선택 할 수 있게 하거나

미리 상수 같은걸 프로그램 실행 시점에서 결정하지 않고 컴파일 시점에서 결정하게 하여

더 빠른 프로그램 속도를 갖게 하는 비법? 꼼수? 학문? 인거 같습니다.

 

진정한 신의 한수... orz....

 

문제는 내가 아직 이걸 프로젝트에 써먹으면서 머리로 이해 + 손으로 익어야 하는데.......

이 개념 자체가 난해하고 어려워서 자료도 그다지 많이 없고

그나마 boost로 익히는 메타프로그래밍 이라는 책을 사서 봤지만....

 

미국 책 스타일... orz...

그냥 개념만 쫙 ~~~ 설명됬고... 제가 멍청해서 그런지 개념 잡기가 너무 난해 하네요..

영어로 표현하면 보는 내내 so what? 이라는 느낌밖에 안왔습니다. ㅠㅠ

 

어쨋든.. 요즘 boost 쪽... 꽤 유용하고 재미있는 프로그래밍 방법론이라 생각하네요..

 

+ Recent posts