boost fusion dynamic at_n

usage

  boost::fusion::vector<int,double,std::string,char> vec(9 ,2.2 ,"aaa" ,'b');
  std::cout << 
   at_n_dynamic<double>(vec, 1) 
    << std::endl; //=> 2.2

detail

#include <boost/fusion/include/vector.hpp>
//#include <boost/fusion/algorithm.hpp>

  template<typename V>
  struct fusion_at_n_functor
  {
    mutable int i;
    int n;
    mutable V value;
    fusion_at_n_functor(int _n):i(0),n(_n){}
    void operator()(const V & t) const
    { if(i==n){value=t;} i++;}  
    template<typename T>
    void operator()(const T & t) const
    { i++;}
  };

  template <typename First,typename Last,typename AtN > void
  at_n_dynamic_fusion_impl(First i,Last last,AtN &atn,boost::mpl::true_ ){}
  template <typename First,typename Last,typename AtN > void
  at_n_dynamic_fusion_impl(First i,Last last,AtN &atn,boost::mpl::false_ ){  
    if(atn.i == atn.n ){atn(boost::fusion::deref(i));}
    else{
      atn(boost::fusion::deref(i));
      at_n_dynamic_fusion_impl(boost::fusion::next(i),last,atn,
			   boost::fusion::result_of::equal_to<
			     typename boost::fusion::result_of::next<First>::type,Last>());}
  }

  template <typename Ret,typename Sequence>  Ret
  at_n_dynamic(Sequence & seq, int n){ 
    fusion_at_n_functor<Ret> atn(n);
#if 0
//debug
    boost::fusion::for_each(seq, atn);
#else
    at_n_dynamic_fusion_impl(boost::fusion::begin(seq),boost::fusion::end(seq) ,atn,
			 boost::fusion::result_of::equal_to<
			   typename boost::fusion::result_of::begin<Sequence>::type,
			   typename boost::fusion::result_of::end<Sequence>::type>());    
#endif
    return atn.value;}
///////////////////////////////////////////////
int main(){
  boost::fusion::vector<int,double,std::string,char> vec(9 ,2.2 ,"aaa" ,'b');
  std::cout << at_n_dynamic<double>(vec, 1) << std::endl; //=> 2.2
}

boost.variantの補助ツール

boost::variant に以下の動作をさせたい

variant<int,int>  => int
variant<int,double>  =>  double
variant<int , boost::rational<int> >   =>   boost::rational<int>
variant<int , double , std::string>   =>   variant<double,std::string>

しかしこうなってくれないので自分で拡張ツールを作った。
https://github.com/niitsuma/variant_shrink

(要するにdecltype(int+double)=>double みたいにまとめられる場合はまとめるけど、まとめられない場合はvariantにしてしまえ,というもの

使用例

C++11が使えない環境でdecltypeの代用品として使う

template<typename X,typename Y> 
typename make_variant_shrink_over<boost::mpl::vector<X,Y> >::type //C++11ならdecltype(x+y)にできる
adder(X x, Y y) {return x + y;} 

double r1= adder(1,1.1); 

boost::rational<int> x(2,3); 
boost::rational<int> r2 = adder(1,x); 

使い方

boost::variant::make_variant_over<boost::mpl::vector<....>  >::type

と同じ様に使う.
ファイル"variant_shrink.hpp"をインクルードするだけで使える

#include "variant_shrink.hpp"

make_variant_shrink_over<boost::mpl::vector<int,int> >::type
=> int

make_variant_shrink_over<boost::mpl::vector<int,boost::rational<int> >::type
=> boost::rational <int>

make_variant_shrink_over<boost::mpl::vector<int,double > >::type
=> double

make_variant_shrink_over<boost::mpl::vector<double,std::string> >::type
=> boost::variant<double,std::string>

make_variant_shrink_over<boost::mpl::vector<double,int,std::string> >::type
=> boost::variant<double,std::string>

任意の縮小方法

デフォルトは

typedef boost::mpl::vector<
         int,boost::rational<int>,float,double,std::complex<double> >::type 
          default_type_order;

となっていて

int <  boost::rational<int>  <  float  < double < std::complex<double> 

の順番で型の一般化(縮約?)がされていく。この順番を変更したい場合は、一般化の順番を決める関数オブジェクトを2番めのテンプレート引数として入力する。例えば

bool  <  int  <  long  <  boost::rational<int>   <  boost::rational<long>

の順番で一般化したい場合は

typedef make_variant_shrink_over<
  boost::mpl::vector<float,bool,boost::rational<long> >       
  , //2番めのテンプレート引数に順番情報を入力する
  generate_mpl_lambda_is_generalizable_to_from_type_order_sequence<      
    boost::mpl::vector<
     bool , int , long , boost::rational<int>  ,  boost::rational<long>  //ここに自分の好きな順番を入れる
      >  
    >::type
  >::type r8type;
BOOST_MPL_ASSERT((boost::mpl::equal<r8type ,boost::variant<boost::rational<long> ,float> > ));

この2番めのテンプレート引数に入力する一般化の順番を決める関数オブジェクト

is_generalizable_to<TypeFrom,TypeTo>

は次のような意味を持つものを作ればよい

is_generalizable_to<float,double> 
 =>  boost::mpl::true_   // float は double に一般化できる
is_generalizable_to<double,float> 
 =>  boost::mpl::false_ //double は float に一般化できない
is_generalizable_to<std::string,float> 
  => boost::mpl::false_  //std::string は floatと比較できない、またはfloatへの一般化はできない。

generate_mpl_lambda_is_generalizable_to_from_type_order_sequenceは一般化の順番ベクトル

generate_mpl_lambda_is_generalizable_to_from_type_order_sequence<   
   boost::mpl::vector<
     bool , int , long , boost::rational<int>  ,  boost::rational<long>
      >  //一般化の順番ベクトル
 >

を入力すると、上記の反応をする関数オブジェクトを生成する。

もっと複雑な縮小順番も入力できる。

浮動小数型:

float < double < long double

整数型:

bool < char < short < int <  long  

の順番で縮約されて、なおかつ浮動小数と整数のunionはboost::variantにしたい場合はこうする。

template<typename T,typename TBase>
struct is_generalizable_to_custom : public
boost::mpl::if_<
  boost::is_floating_point<T>
  , typename boost::mpl::if_< 
     boost::is_floating_point<TBase>
     ,is_less_in_orderd_mpl_sequence<
          T,TBase,boost::mpl::vector<float,double,long double > >  //浮動小数型の順番
     ,boost::mpl::false_                      //浮動小数型と整数型のUnionはそのままvarinatにする
     >::type
 ,typename boost::mpl::if_<
     boost::is_integral<T>
         ,typename boost::mpl::if_<
           boost::is_integral<TBase>
           ,is_less_in_orderd_mpl_sequence<
           T,TBase,boost::mpl::vector<bool,char,short,int,long> > //整数型の順番
           ,boost::mpl::false_
          >::type
         ,boost::mpl::false_  //他の型(std::stringとか)はそのままにする
     >::type 
  >::type
{};

typedef boost::mpl::lambda<is_generalizable_to_custom<
    boost::mpl::_1 , boost::mpl::_2 > >::type 
       is_generalizable_to_custom_mpl_lambda; //boost::mpl::lambdaで包まないと関数オブジェクトとして引数に渡せない

typedef make_variant_shrink_over<
  boost::mpl::vector<double,float,bool,char> 
  ,is_generalizable_to_custom_mpl_lambda //2つ目のtemplate引数として上記で生成した関数オブジェクトを入力
>::type r10type;

BOOST_MPL_ASSERT((boost::mpl::equal<r10type 
   ,boost::variant<double,char> >));

ここで使った補助関数

is_less_in_orderd_mpl_sequence<T1, T2,OrderVector>

is_less_in_orderd_mpl_sequence<int, double ,mpl::vector<bool,int,double,long double> >
 => mpl::true_
is_less_in_orderd_mpl_sequence<double, int ,mpl::vector<bool,int,double,long double> >
 => mpl::false_

のようなT1がT2よりも先に順番ベクトルに出現する時にtrue_となる関数オブジェクト

boost coroutine

scm2cpp

scm2cpp is READABLE C++ code generator from Scheme code.

Ver 0.6

Ver 0.7

  • URL http://www.suri.cs.okayama-u.ac.jp/servlets2/scm2cpp.rkt
  • Feature
    • does not need C++11, C++03 is sufficient
    • Static type inference
      • but sometime can not distinguish int and float
    • Mainly forced on numeric computation
    • Not support symbol and string computation
  • Support
    • uniform vector, uniform list ...
    • More statement can deal than Ver 0.6
  • Not support
    • call/cc , string , char , symbol, switch , car , cdr , cons , let* , letrec , hash , alist ...
    • no difference let let*
    • tail recursion does not expanded
    • some type declaration does not work than Ver0.6
  • Bug in 0.7.2
    • function should not return lambda
    • function should not return do block
  • related work http://www-ti.informatik.uni-tuebingen.de/~weissr/doc/scm2cpp.pdf
  • Require C++ library
    • Boost.Array Boost.Assign Boost.Fusion Boost.Function
  • In ver 0.7.2 following implemented, but not tested.
    • do , named let , cond

scm2cpp benchmark

fft.scm

http://www.suri.cs.okayama-u.ac.jp/~niitsuma/scm2cpp/benchmark/fft.scm

system stalin scm2cpp scm2cpp +openmp scm2cpp +manual rewrite gambit-c chicken racket gauche
i7@2.93GHz ubuntu 0.231 sec 0.407 sec 0.092 sec 0.230 sec 7.408 sec 18.236 sec 6.624 sec 38.055 sec
MacBook core2duo 2.26Ghz - 0.984 - - 16.797 - - -

MacBook
  • Gambit-C
$ time ./fft-gambit 
real	0m16.797s
user	0m13.046s
sys	0m0.135s
  • scm2cpp
$ time ./fft.exe 
real	0m5.202s
user	0m4.298s
sys	0m0.029s
  • scm2cpp with g++ O3
$ time ./fft-O3
real	0m0.984s
user	0m0.807s
sys	0m0.005s

Environment
MacBook core2duo 2.26Ghz
$ uname -a
Darwin 10.8.0 Darwin Kernel Version 10.8.0: Tue Jun 7 16:33:36 PDT 2011; RELEASE_I386 i386

stream-cons & stream-cdr using boost.proto & boost.fusion

#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/algorithm.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/container/list/cons.hpp>
#include <boost/fusion/include/cons.hpp>


#include <boost/proto/proto.hpp>

template<typename T> 
typename boost::proto::result_of::eval<T,boost::proto::default_context >::type	
proto_force(T t){ return boost::proto::eval(t,boost::proto::default_context());	}

template<typename T> 
typename 
boost::proto::result_of::eval<
typename
T::cdr_type::car_type,
boost::proto::default_context >::type
stream_cdr(T t) {	return proto_force((t.cdr).car);}


template<typename T1,typename T2>
typename 
	boost::fusion::cons<T1,
	boost::fusion::cons< 
	typename 
	boost::proto::terminal<T2>::type
	>>
stream_cons(T1 t1 ,T2 t2)
{
	boost::proto::terminal<T2>::type td2={t2};

	boost::fusion::cons< 
	boost::proto::terminal<T2>::type 
	> tc2(td2);

	boost::fusion::cons<T1,
	boost::fusion::cons< 
	boost::proto::terminal<T2>::type
	>> tt(t1,tc2);	

	return tt;
}


int main()
{
auto s= stream_cons(2,stream_cons(1,0));
auto ss= stream_cons(3, s);


	std::cout << proto_force(s.cdr.car).car << std::endl; //ok
	std::cout << proto_force(proto_force(s.cdr.car).cdr.car) << std::endl; //ok

	std::cout << s.car << std::endl;//ok
	std::cout << stream_cdr(s).car  << std::endl;  //ok
	std::cout <<  stream_cdr(ss).car << std::endl; //ok

	std::cout << proto_force(ss.cdr.car).car << std::endl; //ok

	
	std::cout << proto_force(
				 proto_force(ss.cdr.car).cdr.car).car << std::endl; //not work why?

	std::cout <<  stream_cdr(stream_cdr(ss)).car << std::endl; //not work why?

}