qvm/gen/gen.cpp
2017-05-13 21:23:26 -07:00

1910 lines
65 KiB
C++

//Copyright (c) 2008-2017 Emil Dotchevski and Reverge Studios, Inc.
//Distributed under the Boost Software License, Version 1.0. (See accompanying
//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include "boost/throw_exception.hpp"
#include "boost/exception/info.hpp"
#include "boost/exception/diagnostic_information.hpp"
#include "boost/bind.hpp"
#include <string>
#include <map>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <set>
#include <algorithm>
#include <limits>
#include <assert.h>
#define NL "\n"
#define TAB " "
#define TAB1 TAB
#define TAB2 TAB TAB
#define TAB3 TAB TAB TAB
#define TAB4 TAB TAB TAB TAB
#define TAB5 TAB TAB TAB TAB TAB
#define INCLUDE_MAT_ASSIGN "boost/qvm/gen/mat_assign%d.hpp"
#define INCLUDE_VEC_ASSIGN "boost/qvm/gen/vec_assign%d.hpp"
#define INCLUDE_STATIC_ASSERT "boost/qvm/static_assert.hpp"
#define INCLUDE_MATH "boost/qvm/math.hpp"
#define INCLUDE_THROW_EXCEPTION "boost/qvm/throw_exception.hpp"
#define INCLUDE_ERROR "boost/qvm/error.hpp"
#define INCLUDE_INLINE "boost/qvm/inline.hpp"
#define INCLUDE_M_TRAITS "boost/qvm/mat_traits.hpp"
#define INCLUDE_V_TRAITS "boost/qvm/vec_traits.hpp"
#define INCLUDE_Q_TRAITS "boost/qvm/quat_traits.hpp"
#define INCLUDE_S_TRAITS "boost/qvm/scalar_traits.hpp"
#define INCLUDE_DEDUCE_M "boost/qvm/deduce_mat.hpp"
#define INCLUDE_DEDUCE_V "boost/qvm/deduce_vec.hpp"
#define INCLUDE_DEDUCE_Q "boost/qvm/deduce_quat.hpp"
#define INCLUDE_DEDUCE_S "boost/qvm/deduce_scalar.hpp"
#define INCLUDE_SWIZZLE_TRAITS "boost/qvm/detail/swizzle_traits.hpp"
#define INCLUDE_ENABLE_IF "boost/qvm/enable_if.hpp"
#define INCLUDE_ASSERT "boost/qvm/assert.hpp"
namespace
{
struct exception_base: virtual std::exception, virtual boost::exception { };
struct bad_command_line: virtual exception_base { };
typedef boost::error_info<struct cmd_arg_,std::string> cmd_arg;
struct
null_deleter
{
template <class T>
void
operator()( T * ) const
{
}
};
std::string
get_include_guard()
{
std::ostringstream s;
s << std::setw(2) << std::setfill('0') << std::hex << std::uppercase;
s<<"BOOST_QVM_";
for( int i=0; i!=16; ++i )
s<<(rand()%256);
return s.str();
}
template <class T>
std::string
to_string( T const & x )
{
std::ostringstream s;
s<<x;
return s.str();
}
struct
command_line_options
{
bool con;
std::string output_directory;
command_line_options():
con(false)
{
}
};
class
output_file
{
output_file( output_file const & );
output_file & operator=( output_file const & );
std::string const output_directory;
bool const con;
std::ostringstream out_;
std::set<std::string> includes_;
public:
explicit
output_file( command_line_options const & opt ):
output_directory(opt.output_directory),
con(opt.con)
{
}
void
require_include( std::string const & fn )
{
assert(!strchr(fn.c_str(),'%'));
includes_.insert(fn);
};
std::ostream &
stream()
{
return out_;
}
void
dump( std::string const & name ) const
{
std::ostream * out = &std::cout;
boost::shared_ptr<std::ofstream> f;
if( !con )
{
std::string path;
if( !output_directory.empty() )
{
path+=output_directory;
path+='/';
path+=name;
}
boost::shared_ptr<std::ofstream>(new std::ofstream(path.c_str())).swap(f);
out = f.get();
std::cout << "Writing " << path << "..." << std::endl;
}
out->exceptions(std::ofstream::eofbit|std::ofstream::failbit|std::ofstream::badbit);
std::string include_guard=get_include_guard();
*out <<
"//Copyright (c) 2008-2017 Emil Dotchevski and Reverge Studios, Inc." NL
NL
"//Distributed under the Boost Software License, Version 1.0. (See accompanying" NL
"//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)" NL
NL
"#ifndef " << include_guard << NL
"#define " << include_guard << NL
NL
"//This file was generated by a program. Do not edit manually." NL
NL
;
for( std::set<std::string>::const_iterator i=includes_.begin(),e=includes_.end(); i!=e; ++i )
*out << "#include <" << *i << ">" NL;
*out <<
NL
"namespace" NL
"boost" NL
TAB1 "{" NL
TAB1 "namespace" NL
TAB1 "qvm" NL
TAB2 "{" NL <<
out_.str() <<
TAB2 "}" NL
TAB1 "}" NL
NL
"#endif" NL
;
}
};
void
replace( std::string & s, char const * substr, char const * newstr )
{
assert(substr && *substr);
assert(newstr && *newstr);
std::string::size_type f=s.find(substr);
if( s.npos!=f )
s.replace(f,f+strlen(substr),newstr);
}
std::string
deduce_name( std::string const & fn, char const * suffix )
{
std::string s=fn;
replace(s,"operator==","eq");
replace(s,"operator!=","neq");
replace(s,"operator+=","plus_eq");
replace(s,"operator-=","minus_eq");
replace(s,"operator*=","mul_eq");
replace(s,"operator/=","div_eq");
replace(s,"operator+","plus");
replace(s,"operator-","minus");
replace(s,"operator*","mul");
replace(s,"operator/","div");
if( suffix )
{
s += '_';
s += suffix;
}
return s;
}
void
header_mr_ma_mb_same_size( output_file & out, int r, int c, std::string const & name )
{
assert(r>0);
assert(c>0);
assert(!name.empty());
out.require_include(INCLUDE_DEDUCE_M);
out.stream() <<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename lazy_enable_if_c<" NL
TAB3 "mat_traits<A>::rows=="<<r<<" && mat_traits<B>::rows=="<<r<<" &&" NL
TAB3 "mat_traits<A>::cols=="<<c<<" && mat_traits<B>::cols=="<<c<<"," NL
TAB3 "deduce_mat2<A,B,"<<r<<','<<c<<"> >::type" NL
TAB2<<name<<"( A const & a, B const & b )" NL
;
}
void
header_mr_ma_mb_mult( output_file & out, int m, int n, int p, std::string const & name )
{
assert(m>0);
assert(n>0);
assert(p>0);
assert(!name.empty());
out.require_include(INCLUDE_DEDUCE_M);
out.stream()<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename lazy_enable_if_c<" NL
TAB3 "mat_traits<A>::rows=="<<m<<" && mat_traits<B>::rows=="<<n<<" &&" NL
TAB3 "mat_traits<A>::cols=="<<n<<" && mat_traits<B>::cols=="<<p<<"," NL
TAB3 "deduce_mat2<A,B,"<<m<<','<<p<<"> >::type" NL
TAB2<<name<<"( A const & a, B const & b )" NL
;
}
void
header_vr_ma_vb_mult( output_file & out, int r, int c, std::string const & name )
{
assert(r>0);
assert(c>0);
assert(!name.empty());
out.require_include(INCLUDE_DEDUCE_V);
out.stream()<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename lazy_enable_if_c<" NL
TAB3 "mat_traits<A>::rows=="<<r<<" && mat_traits<A>::cols=="<<c<<" &&" NL
TAB3 "vec_traits<B>::dim=="<<c<<"," NL
TAB3 "deduce_vec2<A,B,"<<c<<"> >::type" NL
TAB2<<name<<"( A const & a, B const & b )" NL
;
}
void
header_vr_va_mb_mult( output_file & out, int r, int c, std::string const & name )
{
assert(r>0);
assert(c>0);
assert(!name.empty());
out.require_include(INCLUDE_DEDUCE_V);
out.stream()<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename lazy_enable_if_c<" NL
TAB3 "mat_traits<B>::rows=="<<r<<" && mat_traits<B>::cols=="<<c<<" &&" NL
TAB3 "vec_traits<A>::dim=="<<c<<"," NL
TAB3 "deduce_vec2<A,B,"<<r<<"> >::type" NL
TAB2<<name<<"( A const & a, B const & b )" NL
;
}
void
header_vr_va_vb_same_size( output_file & out, int d, std::string const & name )
{
assert(d>0);
assert(!name.empty());
out.require_include(INCLUDE_DEDUCE_V);
out.stream()<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename lazy_enable_if_c<" NL
TAB3 "vec_traits<A>::dim=="<<d<<" && vec_traits<B>::dim=="<<d<<"," NL
TAB3 "deduce_vec2<A,B,"<<d<<"> >::type" NL
TAB2<<name<<"( A const & a, B const & b )" NL
;
}
void
header_bool_ma_mb_same_size( output_file & out, int r, int c, std::string const & name )
{
assert(r>0);
assert(c>0);
assert(!name.empty());
out.stream()<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename enable_if_c<" NL
TAB3 "mat_traits<A>::rows=="<<r<<" && mat_traits<B>::rows=="<<r<<" &&" NL
TAB3 "mat_traits<A>::cols=="<<c<<" && mat_traits<B>::cols=="<<c<<"," NL
TAB3 "bool>::type" NL
TAB2<<name<<"( A const & a, B const & b )" NL
;
}
void
header_bool_va_vb_same_size( output_file & out, int d, std::string const & name )
{
assert(d>0);
assert(!name.empty());
out.stream()<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename enable_if_c<" NL
TAB3 "vec_traits<A>::dim=="<<d<<" && vec_traits<B>::dim=="<<d<<"," NL
TAB2 "bool>::type" NL
TAB2<<name<<"( A const & a, B const & b )" NL
;
}
void
header_ma_mb_same_size( output_file & out, int r, int c, std::string const & name )
{
assert(r>0);
assert(c>0);
assert(!name.empty());
out.stream()<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename enable_if_c<" NL
TAB3 "mat_traits<A>::rows=="<<r<<" && mat_traits<B>::rows=="<<r<<" &&" NL
TAB3 "mat_traits<A>::cols=="<<c<<" && mat_traits<B>::cols=="<<c<<"," NL
TAB3 "A &>::type" NL
TAB2<<name<<"( A & a, B const & b )" NL
;
}
void
header_va_vb_same_size( output_file & out, int d, std::string const & name )
{
assert(d>0);
assert(!name.empty());
out.stream()<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename enable_if_c<" NL
TAB3 "vec_traits<A>::dim=="<<d<<" && vec_traits<B>::dim=="<<d<<"," NL
TAB3 "A &>::type" NL
TAB2<<name<<"( A & a, B const & b )" NL
;
}
void
header_sr_ma( output_file & out, int r, int c, std::string const & name )
{
assert(r>0);
assert(c>0);
assert(!name.empty());
out.stream()<<
TAB2 "template <class A>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename enable_if_c<" NL
TAB3 "mat_traits<A>::rows=="<<r<<" && mat_traits<A>::cols=="<<c<<"," NL
TAB3 "typename mat_traits<A>::scalar_type>::type" NL
TAB2<<name<<"( A const & a )" NL
;
}
void
header_sr_va_vb( output_file & out, int d, std::string const & name )
{
assert(d>0);
assert(!name.empty());
out.require_include(INCLUDE_DEDUCE_S);
out.stream()<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename lazy_enable_if_c<" NL
TAB3 "vec_traits<A>::dim=="<<d<<" && vec_traits<B>::dim=="<<d<<"," NL
TAB3 "deduce_scalar<typename vec_traits<A>::scalar_type,typename vec_traits<B>::scalar_type> >::type" NL
TAB2<<name<<"( A const & a, B const & b )" NL
;
}
void
header_sr_va( output_file & out, int d, std::string const & name )
{
assert(d>0);
assert(!name.empty());
out.stream()<<
TAB2 "template <class A>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename enable_if_c<" NL
TAB3 "is_vec<A>::value && vec_traits<A>::dim=="<<d<<"," NL
TAB3 "typename vec_traits<A>::scalar_type>::type" NL
TAB2<<name<<"( A const & a )" NL
;
}
void
header_mr_ma( output_file & out, int r, int c, std::string const & name )
{
assert(r>0);
assert(c>0);
assert(!name.empty());
out.require_include(INCLUDE_DEDUCE_M);
out.stream()<<
TAB2 "template <class A>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename lazy_enable_if_c<" NL
TAB3 "mat_traits<A>::rows=="<<r<<" && mat_traits<A>::cols=="<<c<<"," NL
TAB3 "deduce_mat<A> >::type" NL
TAB2<<name<<"( A const & a )" NL
;
}
void
header_vr_va( output_file & out, int d, std::string const & name )
{
assert(d>0);
assert(!name.empty());
out.require_include(INCLUDE_DEDUCE_V);
out.stream()<<
TAB2 "template <class A>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename lazy_enable_if_c<" NL
TAB3 "vec_traits<A>::dim=="<<d<<"," NL
TAB3 "deduce_vec<A> >::type" NL
TAB2<<name<<"( A const & a )" NL
;
}
void
header_vr_va_same_size( output_file & out, int d, std::string const & name )
{
assert(d>0);
assert(!name.empty());
out.stream()<<
TAB2 "template <class R,class A>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename enable_if_c<" NL
TAB3 "is_vec<A>::value &&" NL
TAB3 "vec_traits<R>::dim=="<<d<<" && vec_traits<A>::dim=="<<d<<"," NL
TAB3 "R>::type" NL
TAB2<<name<<"( A const & a )" NL
;
}
void
header_mr_ma_sb( output_file & out, int r, int c, std::string const & name )
{
assert(r>0);
assert(c>0);
assert(!name.empty());
out.require_include(INCLUDE_DEDUCE_M);
out.stream()<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename lazy_enable_if_c<" NL
TAB3 "mat_traits<A>::rows=="<<r<<" && mat_traits<A>::cols=="<<c<<" && is_scalar<B>::value," NL
TAB3 "deduce_mat<A> >::type" NL
TAB2<<name<<"( A const & a, B b )" NL
;
}
void
header_mr_sa_mb( output_file & out, int r, int c, std::string const & name )
{
assert(r>0);
assert(c>0);
assert(!name.empty());
out.require_include(INCLUDE_DEDUCE_M);
out.stream()<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename lazy_enable_if_c<" NL
TAB3 "is_scalar<A>::value && mat_traits<B>::rows=="<<r<<" && mat_traits<B>::cols=="<<c<<"," NL
TAB3 "deduce_mat<B> >::type" NL
TAB2<<name<<"( A a, B const & b )" NL
;
}
void
header_vr_va_sb( output_file & out, int d, std::string const & name )
{
assert(d>0);
assert(!name.empty());
out.require_include(INCLUDE_DEDUCE_V);
out.stream()<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename lazy_enable_if_c<" NL
TAB3 "vec_traits<A>::dim=="<<d<<" && is_scalar<B>::value," NL
TAB3 "deduce_vec<A> >::type" NL
TAB2<<name<<"( A const & a, B b )" NL
;
}
void
header_vr_sa_vb( output_file & out, int d, std::string const & name )
{
assert(d>0);
assert(!name.empty());
out.require_include(INCLUDE_DEDUCE_V);
out.stream()<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename lazy_enable_if_c<" NL
TAB3 "is_scalar<A>::value && vec_traits<B>::dim=="<<d<<"," NL
TAB3 "deduce_vec<B> >::type" NL
TAB2<<name<<"( A a, B const & b )" NL
;
}
void
header_ma_sb( output_file & out, int r, int c, std::string const & name )
{
assert(r>0);
assert(c>0);
assert(!name.empty());
out.stream()<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename enable_if_c<" NL
TAB3 "mat_traits<A>::rows=="<<r<<" && mat_traits<A>::cols=="<<c<<" && is_scalar<B>::value," NL
TAB3 "A &>::type" NL
TAB2<<name<<"( A & a, B b )" NL
;
}
void
header_va_sb( output_file & out, int d, std::string const & name )
{
assert(d>0);
assert(!name.empty());
out.stream()<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename enable_if_c<" NL
TAB3 "vec_traits<A>::dim=="<<d<<" && is_scalar<B>::value," NL
TAB3 "A &>::type" NL
TAB2<<name<<"( A & a, B b )" NL
;
}
void
defined( std::ostream & g, int r, int cr, int c, std::string fn, char const * suffix )
{
assert(r>0);
assert(cr>0);
assert(c>0);
assert(!fn.empty());
std::string dn=deduce_name(fn,suffix);
std::string name=dn+"_defined";
g<<
NL
TAB2 "namespace" NL
TAB2 "sfinae" NL
TAB3 "{" NL
TAB3 "using ::boost::qvm::"<<fn<<";" NL
TAB3 "}" NL
NL
TAB2 "namespace" NL
TAB2 "qvm_detail" NL
TAB3 "{" NL
TAB3 "template <int R,int CR,int C>" NL
TAB3 "struct "<<name<<";" NL
NL
TAB3 "template <>" NL
TAB3 "struct" NL
TAB3<<name<<'<'<<r<<','<<cr<<','<<c<<">" NL
TAB4"{" NL
TAB4"static bool const value=true;" NL
TAB4"};" NL
TAB3 "}" NL
NL
;
}
void
defined( std::ostream & g, int r, int c, std::string const & fn, char const * suffix )
{
assert(r>0);
assert(c>0);
assert(!fn.empty());
std::string dn=deduce_name(fn,suffix);
std::string name=dn+"_defined";
g<<
NL
TAB2 "namespace" NL
TAB2 "sfinae" NL
TAB3 "{" NL
TAB3 "using ::boost::qvm::"<<fn<<";" NL
TAB3 "}" NL
NL
TAB2 "namespace" NL
TAB2 "qvm_detail" NL
TAB3 "{" NL
TAB3 "template <int R,int C>" NL
TAB3 "struct "<<name<<";" NL
NL
TAB3 "template <>" NL
TAB3 "struct" NL
TAB3<<name<<"<"<<r<<","<<c<<">" NL
TAB4"{" NL
TAB4"static bool const value=true;" NL
TAB4"};" NL
TAB3 "}" NL
NL
;
}
void
defined( std::ostream & g, int d, std::string const & fn, char const * suffix )
{
assert(d>0);
assert(!fn.empty());
std::string dn=deduce_name(fn,suffix);
std::string name=dn+"_defined";
g<<
NL
TAB2 "namespace" NL
TAB2 "sfinae" NL
TAB3 "{" NL
TAB3 "using ::boost::qvm::"<<fn<<";" NL
TAB3 "}" NL
NL
TAB2 "namespace" NL
TAB2 "qvm_detail" NL
TAB3 "{" NL
TAB3 "template <int D>" NL
TAB3 "struct "<<name<<";" NL
NL
TAB3 "template <>" NL
TAB3 "struct" NL
TAB3<<name<<"<"<<d<<">" NL
TAB4"{" NL
TAB4"static bool const value=true;" NL
TAB4"};" NL
TAB3 "}" NL
NL
;
}
void
mr_mult_ma_mb( output_file & out, int m, int n, int p, char const * suffix )
{
assert(m>0);
assert(n>0);
assert(p>0);
header_mr_ma_mb_mult(out,m,n,p,"operator*");
out.require_include(INCLUDE_DEDUCE_M);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename mat_traits<A>::scalar_type Ta;" NL
TAB3 "typedef typename mat_traits<B>::scalar_type Tb;" NL
;
for( int i=0; i!=m; ++i )
for( int j=0; j!=n; ++j )
g<<TAB3 "Ta const a"<<i<<j<<" = mat_traits<A>::template read_element<"<<i<<','<<j<<">(a);" NL;
for( int i=0; i!=n; ++i )
for( int j=0; j!=p; ++j )
g<<TAB3 "Tb const b"<<i<<j<<" = mat_traits<B>::template read_element<"<<i<<','<<j<<">(b);" NL;
g<<
TAB3 "typedef typename deduce_mat2<A,B,"<<m<<','<<p<<">::type R;" NL
TAB3 "BOOST_QVM_STATIC_ASSERT(mat_traits<R>::rows=="<<m<<");" NL
TAB3 "BOOST_QVM_STATIC_ASSERT(mat_traits<R>::cols=="<<p<<");" NL
TAB3 "R r;" NL
;
for( int i=0; i!=m; ++i )
for( int j=0; j!=p; ++j )
{
g<<TAB3 "mat_traits<R>::template write_element<"<<i<<","<<j<<">(r)=";
for( int k=0; k!=n; ++k )
{
if( k )
g<<'+';
g<<'a'<<i<<k<<"*b"<<k<<j;
}
g<<";" NL;
}
g<<
TAB3 "return r;" NL
TAB3 "}" NL
;
defined(g,m,n,p,"operator*",suffix);
}
void
ma_mult_ma_mb( output_file & out, int d, char const * suffix )
{
assert(d>0);
header_ma_mb_same_size(out,d,d,"operator*=");
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename mat_traits<A>::scalar_type Ta;" NL
TAB3 "typedef typename mat_traits<B>::scalar_type Tb;" NL
;
for( int i=0; i!=d; ++i )
for( int j=0; j!=d; ++j )
g<<TAB3 "Ta const a"<<i<<j<<" = mat_traits<A>::template read_element<"<<i<<','<<j<<">(a);" NL;
for( int i=0; i!=d; ++i )
for( int j=0; j!=d; ++j )
g<<TAB3 "Tb const b"<<i<<j<<" = mat_traits<B>::template read_element<"<<i<<','<<j<<">(b);" NL;
for( int i=0; i!=d; ++i )
for( int j=0; j!=d; ++j )
{
g<<TAB3 "mat_traits<A>::template write_element<"<<i<<","<<j<<">(a)=";
for( int k=0; k!=d; ++k )
{
if( k )
g<<'+';
g<<'a'<<i<<k<<"*b"<<k<<j;
}
g<<";" NL;
}
g<<
TAB3 "return a;" NL
TAB3 "}" NL
;
defined(g,d,"operator*=",suffix);
}
void
vr_mult_ma_vb( output_file & out, int r, int c, char const * suffix )
{
assert(r>0);
assert(c>0);
header_vr_ma_vb_mult(out,r,c,"operator*");
out.require_include(INCLUDE_INLINE);
out.require_include(INCLUDE_V_TRAITS);
out.require_include(INCLUDE_M_TRAITS);
out.require_include(INCLUDE_ENABLE_IF);
out.require_include(INCLUDE_DEDUCE_V);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename mat_traits<A>::scalar_type Ta;" NL
TAB3 "typedef typename vec_traits<B>::scalar_type Tb;" NL
;
for( int i=0; i!=r; ++i )
for( int j=0; j!=c; ++j )
g<<TAB3 "Ta const a"<<i<<j<<" = mat_traits<A>::template read_element<"<<i<<','<<j<<">(a);" NL;
for( int i=0; i!=c; ++i )
g<<TAB3 "Tb const b"<<i<<" = vec_traits<B>::template read_element<"<<i<<">(b);" NL;
g<<
TAB3 "typedef typename deduce_vec2<A,B,"<<c<<">::type R;" NL
TAB3 "BOOST_QVM_STATIC_ASSERT(vec_traits<R>::dim=="<<c<<");" NL
TAB3 "R r;" NL
;
for( int i=0; i!=r; ++i )
{
g<<TAB3 "vec_traits<R>::template write_element<"<<i<<">(r)=";
for( int j=0; j!=c; ++j )
{
if( j )
g<<'+';
g<<'a'<<i<<j<<"*b"<<j;
}
g<<";" NL;
}
g<<
TAB3 "return r;" NL
TAB3 "}" NL
;
defined(g,r,c,"operator*",suffix);
}
void
vr_mult_va_mb( output_file & out, int r, int c, char const * suffix )
{
assert(r>0);
assert(c>0);
header_vr_va_mb_mult(out,r,c,"operator*");
out.require_include(INCLUDE_INLINE);
out.require_include(INCLUDE_V_TRAITS);
out.require_include(INCLUDE_M_TRAITS);
out.require_include(INCLUDE_ENABLE_IF);
out.require_include(INCLUDE_DEDUCE_V);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename vec_traits<A>::scalar_type Ta;" NL
TAB3 "typedef typename mat_traits<B>::scalar_type Tb;" NL
;
for( int i=0; i!=r; ++i )
g<<TAB3 "Ta const a"<<i<<" = vec_traits<A>::template read_element<"<<i<<">(a);" NL;
for( int i=0; i!=r; ++i )
for( int j=0; j!=c; ++j )
g<<TAB3 "Tb const b"<<i<<j<<" = mat_traits<B>::template read_element<"<<i<<','<<j<<">(b);" NL;
g<<
TAB3 "typedef typename deduce_vec2<A,B,"<<r<<">::type R;" NL
TAB3 "BOOST_QVM_STATIC_ASSERT(vec_traits<R>::dim=="<<r<<");" NL
TAB3 "R r;" NL
;
for( int i=0; i!=c; ++i )
{
g<<TAB3 "vec_traits<R>::template write_element<"<<i<<">(r)=";
for( int j=0; j!=r; ++j )
{
if( j )
g<<'+';
g<<'a'<<j<<"*b"<<j<<i;
}
g<<";" NL;
}
g<<
TAB3 "return r;" NL
TAB3 "}" NL
;
defined(g,r,c,"operator*",suffix);
}
void
vr_op_va_vb_same_size( output_file & out, int d, std::string const & fn, std::string const & op, char const * suffix )
{
assert(!op.empty());
header_vr_va_vb_same_size(out,d,fn);
out.require_include(INCLUDE_DEDUCE_V);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename deduce_vec2<A,B,"<<d<<">::type R;" NL
TAB3 "BOOST_QVM_STATIC_ASSERT(vec_traits<R>::dim=="<<d<<");" NL
TAB3 "R r;" NL
;
for( int i=0; i!=d; ++i )
g<<TAB3 "vec_traits<R>::template write_element<"<<i<<">(r)=vec_traits<A>::template read_element<"<<i<<">(a)"<<op<<"vec_traits<B>::template read_element<"<<i<<">(b);" NL;
g<<
TAB3 "return r;" NL
TAB3 "}" NL
;
defined(g,d,fn,suffix);
}
void
bool_eq_ma_mb( output_file & out, int r, int c, char const * suffix )
{
header_bool_ma_mb_same_size(out,r,c,"operator==");
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "return" NL
;
for( int i=0; i!=r; ++i )
for( int j=0; j!=c; ++j )
g<<
TAB4"mat_traits<A>::template read_element<"<<i<<','<<j<<">(a)==mat_traits<B>::template read_element<"<<i<<','<<j<<">(b)"<<(i!=r-1||j!=c-1?" &&":";")<<NL;
;
g<<
TAB3 "}" NL
;
defined(g,r,c,"operator==",suffix);
}
void
bool_eq_va_vb( output_file & out, int d, char const * suffix )
{
header_bool_va_vb_same_size(out,d,"operator==");
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "return" NL
;
for( int i=0; i!=d; ++i )
g<<
TAB4"vec_traits<A>::template read_element<"<<i<<">(a)==vec_traits<B>::template read_element<"<<i<<">(b)"<<(i!=d-1?" &&":";")<<NL;
;
g<<
TAB3 "}" NL
;
defined(g,d,"operator==",suffix);
}
void
bool_neq_ma_mb( output_file & out, int r, int c, char const * suffix )
{
header_bool_ma_mb_same_size(out,r,c,"operator!=");
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "return" NL
;
for( int i=0; i!=r; ++i )
for( int j=0; j!=c; ++j )
g<<
TAB4"!(mat_traits<A>::template read_element<"<<i<<','<<j<<">(a)==mat_traits<B>::template read_element<"<<i<<','<<j<<">(b))"<<(i!=r-1||j!=c-1?" ||":";")<<NL;
;
g<<
TAB3 "}" NL
;
defined(g,r,c,"operator!=",suffix);
}
void
bool_neq_va_vb( output_file & out, int d, char const * suffix )
{
header_bool_va_vb_same_size(out,d,"operator!=");
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "return" NL
;
for( int i=0; i!=d; ++i )
g<<
TAB4"!(vec_traits<A>::template read_element<"<<i<<">(a)==vec_traits<B>::template read_element<"<<i<<">(b))"<<(i!=d-1?" ||":";")<<NL;
;
g<<
TAB3 "}" NL
;
defined(g,d,"operator!=",suffix);
}
void
mr_op_ma_mb_same_size( output_file & out, int r, int c, std::string const & fn, std::string const & op, char const * suffix )
{
assert(r>0);
assert(c>0);
assert(!op.empty());
header_mr_ma_mb_same_size(out,r,c,fn);
out.require_include(INCLUDE_DEDUCE_M);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename deduce_mat2<A,B,"<<r<<','<<c<<">::type R;" NL
TAB3 "BOOST_QVM_STATIC_ASSERT(mat_traits<R>::rows=="<<r<<");" NL
TAB3 "BOOST_QVM_STATIC_ASSERT(mat_traits<R>::cols=="<<c<<");" NL
TAB3 "R r;" NL
;
for( int i=0; i!=r; ++i )
for( int j=0; j!=c; ++j )
g<<TAB3 "mat_traits<R>::template write_element<"<<i<<","<<j<<">(r)=mat_traits<A>::template read_element<"<<i<<","<<j<<">(a)"<<op<<"mat_traits<B>::template read_element<"<<i<<","<<j<<">(b);" NL;
g<<
TAB3 "return r;" NL
TAB3 "}" NL
;
defined(g,r,c,fn,suffix);
}
void
ma_op_ma_mb_same_size( output_file & out, int r, int c, std::string const & fn, std::string const & op, char const * suffix )
{
assert(!op.empty());
header_ma_mb_same_size(out,r,c,fn);
std::ostream & g=out.stream();
g<<TAB3 "{" NL;
for( int i=0; i!=r; ++i )
for( int j=0; j!=c; ++j )
g<<TAB3 "mat_traits<A>::template write_element<"<<i<<","<<j<<">(a)"<<op<<"mat_traits<B>::template read_element<"<<i<<","<<j<<">(b);" NL;
g<<
TAB3 "return a;" NL
TAB3 "}" NL
;
defined(g,r,c,fn,suffix);
}
void
va_op_va_vb_same_size( output_file & out, int d, std::string const & fn, std::string const & op, char const * suffix )
{
assert(!op.empty());
header_va_vb_same_size(out,d,fn);
std::ostream & g=out.stream();
g<<TAB3 "{" NL;
for( int i=0; i!=d; ++i )
g<<TAB3 "vec_traits<A>::template write_element<"<<i<<">(a)"<<op<<"vec_traits<B>::template read_element<"<<i<<">(b);" NL;
g<<
TAB3 "return a;" NL
TAB3 "}" NL
;
defined(g,d,fn,suffix);
}
void
mr_op_ma( output_file & out, int r, int c, std::string const & fn, std::string const & op, char const * suffix )
{
assert(!op.empty());
header_mr_ma(out,r,c,fn);
out.require_include(INCLUDE_DEDUCE_M);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename deduce_mat<A>::type R;" NL
TAB3 "R r;" NL
;
for( int i=0; i!=r; ++i )
for( int j=0; j!=c; ++j )
g<<TAB3 "mat_traits<R>::template write_element<"<<i<<","<<j<<">(r)="<<op<<"mat_traits<A>::template read_element<"<<i<<","<<j<<">(a);" NL;
g<<
TAB3 "return r;" NL
TAB3 "}" NL
;
defined(g,r,c,fn,suffix);
}
void
vr_op_va( output_file & out, int d, std::string const & fn, std::string const & op, char const * suffix )
{
assert(!op.empty());
header_vr_va(out,d,fn);
out.require_include(INCLUDE_DEDUCE_V);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename deduce_vec<A>::type R;" NL
TAB3 "R r;" NL
;
for( int i=0; i!=d; ++i )
g<<TAB3 "vec_traits<R>::template write_element<"<<i<<">(r)="<<op<<"vec_traits<A>::template read_element<"<<i<<">(a);" NL;
g<<
TAB3 "return r;" NL
TAB3 "}" NL
;
defined(g,d,fn,suffix);
}
void
mr_op_ma_sb( output_file & out, int r, int c, std::string const & fn, std::string const & op, char const * suffix )
{
assert(!op.empty());
header_mr_ma_sb(out,r,c,fn);
out.require_include(INCLUDE_DEDUCE_M);
out.require_include(INCLUDE_DEDUCE_V);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename deduce_mat<A>::type R;" NL
TAB3 "R r;" NL
;
for( int i=0; i!=r; ++i )
for( int j=0; j!=c; ++j )
g<<TAB3 "mat_traits<R>::template write_element<"<<i<<","<<j<<">(r)=mat_traits<A>::template read_element<"<<i<<","<<j<<">(a)"<<op<<"b;" NL;
g<<
TAB3 "return r;" NL
TAB3 "}" NL
;
defined(g,r,c,fn,suffix);
}
void
mr_op_sa_mb( output_file & out, int r, int c, std::string const & fn, std::string const & op, char const * suffix )
{
assert(!op.empty());
header_mr_sa_mb(out,r,c,fn);
out.require_include(INCLUDE_DEDUCE_M);
out.require_include(INCLUDE_DEDUCE_V);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename deduce_mat<B>::type R;" NL
TAB3 "R r;" NL
;
for( int i=0; i!=r; ++i )
for( int j=0; j!=c; ++j )
g<<TAB3 "mat_traits<R>::template write_element<"<<i<<","<<j<<">(r)=a"<<op<<"mat_traits<B>::template read_element<"<<i<<","<<j<<">(b);" NL;
g<<
TAB3 "return r;" NL
TAB3 "}" NL
;
defined(g,r,c,fn,suffix);
}
void
vr_op_va_sb( output_file & out, int d, std::string const & fn, std::string const & op, char const * suffix )
{
assert(!op.empty());
header_vr_va_sb(out,d,fn);
out.require_include(INCLUDE_DEDUCE_V);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename deduce_vec<A>::type R;" NL
TAB3 "R r;" NL
;
for( int i=0; i!=d; ++i )
g<<TAB3 "vec_traits<R>::template write_element<"<<i<<">(r)=vec_traits<A>::template read_element<"<<i<<">(a)"<<op<<"b;" NL;
g<<
TAB3 "return r;" NL
TAB3 "}" NL
;
defined(g,d,fn,suffix);
}
void
vr_op_sa_vb( output_file & out, int d, std::string const & fn, std::string const & op, char const * suffix )
{
assert(!op.empty());
header_vr_sa_vb(out,d,fn);
out.require_include(INCLUDE_DEDUCE_V);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename deduce_vec<B>::type R;" NL
TAB3 "R r;" NL
;
for( int i=0; i!=d; ++i )
g<<TAB3 "vec_traits<R>::template write_element<"<<i<<">(r)=a"<<op<<"vec_traits<B>::template read_element<"<<i<<">(b);" NL;
g<<
TAB3 "return r;" NL
TAB3 "}" NL
;
defined(g,d,fn,suffix);
}
void
ma_op_ma_sb( output_file & out, int r, int c, std::string const & fn, std::string const & op, char const * suffix )
{
assert(!op.empty());
header_ma_sb(out,r,c,fn);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
;
for( int i=0; i!=r; ++i )
for( int j=0; j!=c; ++j )
g<<TAB3 "mat_traits<A>::template write_element<"<<i<<","<<j<<">(a)"<<op<<"b;" NL;
g<<
TAB3 "return a;" NL
TAB3 "}" NL
;
defined(g,r,c,fn,suffix);
}
void
va_op_va_sb( output_file & out, int d, std::string const & fn, std::string const & op, char const * suffix )
{
assert(!op.empty());
header_va_sb(out,d,fn);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
;
for( int i=0; i!=d; ++i )
g<<TAB3 "vec_traits<A>::template write_element<"<<i<<">(a)"<<op<<"b;" NL;
g<<
TAB3 "return a;" NL
TAB3 "}" NL
;
defined(g,d,fn,suffix);
}
void
ma_assign_ma_mb( output_file & out, int r, int c, char const * suffix )
{
header_ma_mb_same_size(out,r,c,"assign");
out.require_include(INCLUDE_M_TRAITS);
out.require_include(INCLUDE_INLINE);
out.require_include(INCLUDE_ENABLE_IF);
std::ostream & g=out.stream();
g<<TAB3 "{" NL;
for( int i=0; i!=r; ++i )
for( int j=0; j!=c; ++j )
g<<TAB3 "mat_traits<A>::template write_element<"<<i<<","<<j<<">(a)=mat_traits<B>::template read_element<"<<i<<","<<j<<">(b);" NL;
g<<
TAB3 "return a;" NL
TAB3 "}" NL
;
defined(g,r,c,"assign",suffix);
}
void
va_assign_va_vb( output_file & out, int d, char const * suffix )
{
header_va_vb_same_size(out,d,"assign");
out.require_include(INCLUDE_V_TRAITS);
out.require_include(INCLUDE_INLINE);
out.require_include(INCLUDE_ENABLE_IF);
std::ostream & g=out.stream();
g<<TAB3 "{" NL;
for( int i=0; i!=d; ++i )
g<<TAB3 "vec_traits<A>::template write_element<"<<i<<">(a)=vec_traits<B>::template read_element<"<<i<<">(b);" NL;
g<<
TAB3 "return a;" NL
TAB3 "}" NL
;
defined(g,d,"assign",suffix);
}
void
mr_convert_to_ma( output_file & out, int r, int c, char const * suffix )
{
if( r==c && r>=3 )
{
out.require_include(INCLUDE_Q_TRAITS);
out.require_include(INCLUDE_S_TRAITS);
}
std::ostream & g=out.stream();
g<<
TAB2 "template <class R,class A>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename enable_if_c<" NL
TAB3 "mat_traits<R>::rows=="<<r<<" && mat_traits<A>::rows=="<<r<<" &&" NL
TAB3 "mat_traits<R>::cols=="<<c<<" && mat_traits<A>::cols=="<<c<<"," NL
TAB3 "R>::type" NL
TAB2<<"convert_to( A const & a )" NL
TAB3 "{" NL
TAB3 "R r;" NL
;
for( int i=0; i!=r; ++i )
for( int j=0; j!=c; ++j )
g<<TAB3 "mat_traits<R>::template write_element<"<<i<<","<<j<<">(r) = mat_traits<A>::template read_element<"<<i<<","<<j<<">(a);" NL;
g<<
TAB3 "return r;" NL
TAB3 "}" NL
;
if( r==c && r>=3 )
{
g<<
NL
TAB2 "template <class R,class A>" NL
TAB2 "BOOST_QVM_INLINE" NL
TAB2 "typename enable_if_c<" NL
TAB3 "is_mat<R>::value && is_quat<A>::value &&" NL
TAB3 "mat_traits<R>::rows=="<<r<<" && mat_traits<R>::cols=="<<c<<"," NL
TAB3 "R>::type" NL
TAB2 "convert_to( A const & q )" NL
TAB3 "{" NL
TAB3 "typedef typename mat_traits<R>::scalar_type T;" NL
TAB3 "T const a=quat_traits<A>::template read_element<0>(q);" NL
TAB3 "T const b=quat_traits<A>::template read_element<1>(q);" NL
TAB3 "T const c=quat_traits<A>::template read_element<2>(q);" NL
TAB3 "T const d=quat_traits<A>::template read_element<3>(q);" NL
TAB3 "T const bb = b*b;" NL
TAB3 "T const cc = c*c;" NL
TAB3 "T const dd = d*d;" NL
TAB3 "T const bc = b*c;" NL
TAB3 "T const bd = b*d;" NL
TAB3 "T const cd = c*d;" NL
TAB3 "T const ab = a*b;" NL
TAB3 "T const ac = a*c;" NL
TAB3 "T const ad = a*d;" NL<<
(r>3?TAB3 "T const zero = scalar_traits<T>::value(0);" NL:"")<<
TAB3 "T const one = scalar_traits<T>::value(1);" NL
TAB3 "T const two = one+one;" NL
TAB3 "R r;" NL
TAB3 "mat_traits<R>::template write_element<0,0>(r) = one - two*(cc+dd);" NL
TAB3 "mat_traits<R>::template write_element<0,1>(r) = two*(bc-ad);" NL
TAB3 "mat_traits<R>::template write_element<0,2>(r) = two*(bd+ac);" NL
;
for( int i=3; i!=c; ++i )
g<<TAB3 "mat_traits<R>::template write_element<0,"<<i<<">(r) = zero;" NL;
g<<
TAB3 "mat_traits<R>::template write_element<1,0>(r) = two*(bc+ad);" NL
TAB3 "mat_traits<R>::template write_element<1,1>(r) = one - two*(bb+dd);" NL
TAB3 "mat_traits<R>::template write_element<1,2>(r) = two*(cd-ab);" NL
;
for( int i=3; i!=c; ++i )
g<<TAB3 "mat_traits<R>::template write_element<1,"<<i<<">(r) = zero;" NL;
g<<
TAB3 "mat_traits<R>::template write_element<2,0>(r) = two*(bd-ac);" NL
TAB3 "mat_traits<R>::template write_element<2,1>(r) = two*(cd+ab);" NL
TAB3 "mat_traits<R>::template write_element<2,2>(r) = one - two*(bb+cc);" NL
;
for( int i=3; i!=c; ++i )
g<<TAB3 "mat_traits<R>::template write_element<2,"<<i<<">(r) = zero;" NL;
for( int i=3; i!=r; ++i )
for( int j=0; j!=c; ++j )
g<<TAB3 "mat_traits<R>::template write_element<"<<i<<","<<j<<">(r) = "<<(i==j?"one":"zero")<<";" NL;
g<<
TAB3 "return r;" NL
TAB3 "}" NL
;
}
defined(g,r,c,"convert_to",suffix);
}
void
vr_convert_to_va( output_file & out, int d, char const * suffix )
{
header_vr_va_same_size(out,d,"convert_to");
std::ostream & g=out.stream();
g<<TAB3 "{" NL<<
TAB3 "R r;" NL
;
for( int i=0; i!=d; ++i )
g<<TAB3 "vec_traits<R>::template write_element<"<<i<<">(r)=vec_traits<A>::template read_element<"<<i<<">(a);" NL;
g<<
TAB3 "return r;" NL
TAB3 "}" NL
;
defined(g,d,"convert_to",suffix);
}
struct
del_row_col
{
del_row_col const * next;
int i, j;
char var;
explicit
del_row_col( char var ):
next(0),
i(std::numeric_limits<int>::max()),
j(std::numeric_limits<int>::max()),
var(var)
{
}
del_row_col( del_row_col const & next, int i, int j ):
next(&next),
i(i),
j(j),
var(next.var)
{
}
std::pair<int,int>
idx( std::pair<int,int> const & x ) const
{
std::pair<int,int> r(x.first+(x.first>=i),x.second+(x.second>=j));
if( next )
return next->idx(r);
else
return r;
}
void
operator()( std::ostream & g, int r, int c ) const
{
std::pair<int,int> p=idx(std::make_pair(r,c));
g << var << p.first << p.second;
}
};
void
determinant_impl( std::ostream & g, int n, del_row_col const & a )
{
if( n==1 )
return a(g,0,0);
g << "(";
char const * plus="";
for( int i=0; i!=n; ++i,plus="+" )
{
g<<((i&1)?"-":plus);
a(g,0,i);
g<<'*';
determinant_impl(g,n-1,del_row_col(a,0,i));
}
g << ")";
}
void
determinant( output_file & out, int d, char const * suffix )
{
header_sr_ma(out,d,d,"determinant");
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename mat_traits<A>::scalar_type T;" NL
;
for( int i=0; i!=d; ++i )
for( int j=0; j!=d; ++j )
g<<TAB3<<"T const a"<<i<<j<<"=mat_traits<A>::template read_element<"<<i<<','<<j<<">(a);" NL;
g<<TAB3 "T det=";
determinant_impl(g,d,del_row_col('a'));
g<<";" NL;
g<<
TAB3 "return det;" NL
TAB3 "}" NL
;
defined(g,d,"determinant",suffix);
}
void
inverse_ma( output_file & out, int d, char const * suffix )
{
assert(d>1);
out.require_include(INCLUDE_DEDUCE_M);
out.require_include(INCLUDE_ASSERT);
out.require_include(INCLUDE_THROW_EXCEPTION);
out.require_include(INCLUDE_ERROR);
std::ostream & g=out.stream();
g<<
TAB2 "template <class A,class B>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename lazy_enable_if_c<" NL
TAB3 "mat_traits<A>::rows=="<<d<<" && mat_traits<A>::cols=="<<d<<" && is_scalar<B>::value," NL
TAB3 "deduce_mat<A> >::type" NL
TAB2 "inverse( A const & a, B det )" NL
TAB3 "{" NL
TAB3 "typedef typename mat_traits<A>::scalar_type T;" NL
TAB3 "BOOST_QVM_ASSERT(det!=scalar_traits<B>::value(0));" NL
;
for( int i=0; i!=d; ++i )
for( int j=0; j!=d; ++j )
g<<TAB3 "T const a"<<i<<j<<"=mat_traits<A>::template read_element<"<<i<<','<<j<<">(a);" NL;
g<<
TAB3 "T const f=scalar_traits<T>::value(1)/det;" NL
TAB3 "typedef typename deduce_mat<A>::type R;" NL
TAB3 "R r;" NL
;
for( int i=0; i!=d; ++i )
for( int j=0; j!=d; ++j )
{
g<<TAB3 "mat_traits<R>::template write_element<"<<i<<','<<j<<">(r)="<<(((i+j)&1)?'-':' ')<<"f*";
determinant_impl(g,d-1,del_row_col(del_row_col('a'),j,i));
g<<";" NL;
}
g<<
TAB3 "return r;" NL
TAB3 "}" NL
NL
TAB2 "template <class A>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename lazy_enable_if_c<" NL
TAB3 "mat_traits<A>::rows=="<<d<<" && mat_traits<A>::cols=="<<d<<"," NL
TAB3 "deduce_mat<A> >::type" NL
TAB2 "inverse( A const & a )" NL
TAB3 "{" NL
TAB3 "typedef typename mat_traits<A>::scalar_type T;" NL
TAB3 "T det=determinant(a);" NL
TAB3 "if( det==scalar_traits<T>::value(0) )" NL
TAB4"BOOST_QVM_THROW_EXCEPTION(zero_determinant_error());" NL
TAB3 "return inverse(a,det);" NL
TAB3 "}" NL
;
defined(g,d,"inverse",suffix);
}
void
mag_sqr( output_file & out, int d, char const * suffix )
{
header_sr_va(out,d,"mag_sqr");
out.require_include(INCLUDE_MATH);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename vec_traits<A>::scalar_type T;" NL
;
for( int i=0; i!=d; ++i )
g<<TAB3 "T const a"<<i<<"=vec_traits<A>::template read_element<"<<i<<">(a);" NL;
g<<TAB3 "T const m2=";
for( int i=0; i!=d; ++i )
{
if( i )
g<<'+';
g<<'a'<<i<<"*a"<<i;
}
g<<
";" NL
TAB3 "return m2;" NL
TAB3 "}" NL
;
defined(g,d,"mag_sqr",suffix);
}
void
mag( output_file & out, int d, char const * suffix )
{
header_sr_va(out,d,"mag");
out.require_include(INCLUDE_MATH);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename vec_traits<A>::scalar_type T;" NL
;
for( int i=0; i!=d; ++i )
g<<TAB3 "T const a"<<i<<"=vec_traits<A>::template read_element<"<<i<<">(a);" NL;
g<<TAB3 "T const m2=";
for( int i=0; i!=d; ++i )
{
if( i )
g<<'+';
g<<'a'<<i<<"*a"<<i;
}
g<<
";" NL
TAB3 "T const mag=sqrt<T>(m2);" NL
TAB3 "return mag;" NL
TAB3 "}" NL
;
defined(g,d,"mag",suffix);
}
void
normalize( output_file & out, int d, char const * suffix )
{
header_vr_va(out,d,"normalized");
out.require_include(INCLUDE_MATH);
out.require_include(INCLUDE_THROW_EXCEPTION);
out.require_include(INCLUDE_ERROR);
out.require_include(INCLUDE_DEDUCE_V);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename vec_traits<A>::scalar_type T;" NL
;
for( int i=0; i!=d; ++i )
g<<TAB3 "T const a"<<i<<"=vec_traits<A>::template read_element<"<<i<<">(a);" NL;
g<<TAB3 "T const m2=";
for( int i=0; i!=d; ++i )
{
if( i )
g<<'+';
g<<'a'<<i<<"*a"<<i;
}
g<<
";" NL
TAB3 "if( m2==scalar_traits<typename vec_traits<A>::scalar_type>::value(0) )" NL
TAB4"BOOST_QVM_THROW_EXCEPTION(zero_magnitude_error());" NL
TAB3 "T const rm=scalar_traits<T>::value(1)/sqrt<T>(m2);" NL
TAB3 "typedef typename deduce_vec<A>::type R;" NL
TAB3 "R r;" NL
;
for( int i=0; i!=d; ++i )
g<<TAB3 "vec_traits<R>::template write_element<"<<i<<">(r)=a"<<i<<"*rm;" NL;
g<<
TAB3 "return r;" NL
TAB3 "}" NL
NL
TAB2 "namespace" NL
TAB2 "sfinae" NL
TAB3 "{" NL
TAB3 "using ::boost::qvm::normalized;" NL
TAB3 "}" NL
NL
TAB2 "template <class A>" NL
TAB2 "BOOST_QVM_INLINE_OPERATIONS" NL
TAB2 "typename enable_if_c<" NL
TAB3 "vec_traits<A>::dim=="<<d<<"," NL
TAB3 "void>::type" NL
TAB2<<"normalize( A & a )" NL
TAB3 "{" NL
TAB3 "typedef typename vec_traits<A>::scalar_type T;" NL
;
for( int i=0; i!=d; ++i )
g<<TAB3 "T const a"<<i<<"=vec_traits<A>::template read_element<"<<i<<">(a);" NL;
g<<TAB3 "T const m2=";
for( int i=0; i!=d; ++i )
{
if( i )
g<<'+';
g<<'a'<<i<<"*a"<<i;
}
g<<
";" NL
TAB3 "if( m2==scalar_traits<typename vec_traits<A>::scalar_type>::value(0) )" NL
TAB4"BOOST_QVM_THROW_EXCEPTION(zero_magnitude_error());" NL
TAB3 "T const rm=scalar_traits<T>::value(1)/sqrt<T>(m2);" NL
;
for( int i=0; i!=d; ++i )
g<<TAB3 "vec_traits<A>::template write_element<"<<i<<">(a)*=rm;" NL;
g<<TAB3 "}" NL;
defined(g,d,"normalize",suffix);
}
void
dot( output_file & out, int d, char const * suffix )
{
header_sr_va_vb(out,d,"dot");
out.require_include(INCLUDE_DEDUCE_S);
out.require_include(INCLUDE_STATIC_ASSERT);
std::ostream & g=out.stream();
g<<
TAB3 "{" NL
TAB3 "typedef typename vec_traits<A>::scalar_type Ta;" NL
TAB3 "typedef typename vec_traits<B>::scalar_type Tb;" NL
TAB3 "typedef typename deduce_scalar<Ta,Tb>::type Tr;" NL
;
for( int i=0; i!=d; ++i )
g<<TAB3 "Ta const a"<<i<<"=vec_traits<A>::template read_element<"<<i<<">(a);" NL;
for( int i=0; i!=d; ++i )
g<<TAB3 "Tb const b"<<i<<"=vec_traits<B>::template read_element<"<<i<<">(b);" NL;
g<<TAB3 "Tr const dot=";
for( int i=0; i!=d; ++i )
{
if( i )
g<<'+';
g<<'a'<<i<<"*b"<<i;
}
g<<
";" NL
TAB3 "return dot;" NL
TAB3 "}" NL
;
defined(g,d,"dot",suffix);
}
struct
swizzle_pair
{
char ch;
int idx;
};
template <int N>
void
swizzle_impl( std::ostream & g, int d, swizzle_pair const (&ids)[N], std::vector<int> const & initial_count )
{
assert(d>=2);
std::vector<int> count(initial_count);
for( char const * const ref_id[2] = { " const &", " &" };; )
{
int max_dim=-100;
for( int i=0; i!=d; ++i )
max_dim=std::max(max_dim,ids[count[i]-1].idx);
if( max_dim<0 )
{
g<<
TAB2 "BOOST_QVM_INLINE_TRIVIAL" NL
TAB2 "qvm_detail::sw01_<";
for( int k=0; k!=d; ++k )
g<<(k?",":"")<<"qvm_detail::swizzle_idx<"<<ids[count[k]-1].idx;
for( int k=0; k!=d; ++k )
g<<" >";
g<<
" > const &" NL
TAB2 "_";
for( int k=0; k!=d; ++k )
{
char f=ids[count[k]-1].ch;
assert(f>='0' && f<='9');
g<<f;
}
g<<
"()" NL
TAB3 "{" NL
TAB3 "return *reinterpret_cast<qvm_detail::sw01_<";
for( int k=0; k!=d; ++k )
g<<(k?",":"")<<"qvm_detail::swizzle_idx<"<<ids[count[k]-1].idx;
for( int k=0; k!=d; ++k )
g<<" >";
g<<
" > const *>(qvm_detail::get_null());" NL
TAB3 "}" NL;
}
else
for( int rfid=0; rfid<2; ++rfid )
{
for( int scalar=0; scalar!=2; ++scalar )
{
if( scalar && max_dim>0 )
break;
if( scalar )
g<<
TAB2 "template <class S>" NL
TAB2 "BOOST_QVM_INLINE_TRIVIAL" NL
TAB2 "typename enable_if_c<" NL
TAB3 "is_scalar<S>::value," NL
TAB3 "qvm_detail::sws_<S,";
else
g<<
TAB2 "template <class V>" NL
TAB2 "BOOST_QVM_INLINE_TRIVIAL" NL
TAB2 "typename enable_if_c<" NL
TAB3 "is_vec<V>::value && vec_traits<V>::dim>="<<max_dim+1<<"," NL
TAB3 "qvm_detail::sw_<V,";
for( int k=0; k!=d; ++k )
g<<(k?",":"")<<"qvm_detail::swizzle_idx<"<<ids[count[k]-1].idx;
for( int k=0; k!=d; ++k )
g<<" >";
g<<" >"<<ref_id[rfid]<<">::type" NL TAB2;
for( int k=0; k!=d; ++k )
{
char f=ids[count[k]-1].ch;
if( !k && f>='0' && f<='9' )
g<<'_';
g<<f;
}
if( scalar )
g<<
"( S"<<ref_id[rfid]<<" a )" NL
TAB3 "{" NL
TAB3 "return reinterpret_cast<qvm_detail::sws_<S,";
else
g<<
"( V"<<ref_id[rfid]<<" a )" NL
TAB3 "{" NL
TAB3 "return reinterpret_cast<qvm_detail::sw_<V,";
for( int k=0; k!=d; ++k )
g<<(k?",":"")<<"qvm_detail::swizzle_idx<"<<ids[count[k]-1].idx;
for( int k=0; k!=d; ++k )
g<<" >";
g<<
" >"<<ref_id[rfid]<<">(a);" NL
TAB3 "}" NL;
}
}
int j;
for( j=0; j!=d; ++j )
if( --count[j] )
break;
else
count[j]=initial_count[j];
if( j==d )
break;
}
}
void
swizzle( output_file & out, int d )
{
assert(d>1);
out.require_include(INCLUDE_INLINE);
out.require_include(INCLUDE_SWIZZLE_TRAITS);
out.require_include(INCLUDE_ENABLE_IF);
std::ostream & g=out.stream();
swizzle_pair const swizzle_ids[6] =
{
{'X',0},
{'Y',1},
{'Z',2},
{'W',3},
{'0',-1},
{'1',-2}
};
std::vector<int> initial_count(d,6);
swizzle_impl(g,d,swizzle_ids,initial_count);
}
command_line_options
parse_command_line( int argc, char const * argv[] )
{
class
next
{
char const * const * const argv;
public:
int const argc;
next( int argc, char const * argv[] ):
argc(argc),
argv(argv)
{
}
std::string
operator()( int & i ) const
{
assert(i<argc);
if( ++i==argc )
BOOST_THROW_EXCEPTION(bad_command_line() << cmd_arg(argv[i-1]));
return argv[i];
}
} next_token(argc,argv);
command_line_options r;
for( int i=1; i!=argc; ++i )
if( argv[i][0]=='-' )
{
char const * arg=argv[i];
if( arg==std::string("-od") )
r.output_directory=next_token(i);
else if( arg==std::string("-con") )
r.con=true;
else
BOOST_THROW_EXCEPTION(bad_command_line() << cmd_arg(arg));
}
return r;
}
void
gen( int argc, char const * argv[] )
{
command_line_options opt=parse_command_line(argc,argv);
for( int d=2; d!=5; ++d )
{
output_file f(opt);
{
char buf[1024];
sprintf(buf,INCLUDE_MAT_ASSIGN,d);
f.require_include(buf);
}
mr_op_ma_mb_same_size(f,d,d,"operator+","+","mm");
mr_op_ma_mb_same_size(f,d,1,"operator+","+","mm");
mr_op_ma_mb_same_size(f,1,d,"operator+","+","mm");
mr_op_ma_mb_same_size(f,d,d,"operator-","-","mm");
mr_op_ma_mb_same_size(f,d,1,"operator-","-","mm");
mr_op_ma_mb_same_size(f,1,d,"operator-","-","mm");
ma_op_ma_mb_same_size(f,d,d,"operator+=","+=","mm");
ma_op_ma_mb_same_size(f,d,1,"operator+=","+=","mm");
ma_op_ma_mb_same_size(f,1,d,"operator+=","+=","mm");
ma_op_ma_mb_same_size(f,d,d,"operator-=","-=","mm");
ma_op_ma_mb_same_size(f,d,1,"operator-=","-=","mm");
ma_op_ma_mb_same_size(f,1,d,"operator-=","-=","mm");
mr_op_ma_sb(f,d,d,"operator*","*","ms");
mr_op_sa_mb(f,d,d,"operator*","*","sm");
mr_op_ma_sb(f,d,1,"operator*","*","ms");
mr_op_sa_mb(f,d,1,"operator*","*","sm");
mr_op_ma_sb(f,1,d,"operator*","*","ms");
mr_op_sa_mb(f,1,d,"operator*","*","sm");
ma_op_ma_sb(f,d,d,"operator*=","*=","ms");
ma_op_ma_sb(f,d,1,"operator*=","*=","ms");
ma_op_ma_sb(f,1,d,"operator*=","*=","ms");
mr_op_ma_sb(f,d,d,"operator/","/","ms");
mr_op_sa_mb(f,d,d,"operator/","/","sm");
mr_op_ma_sb(f,d,1,"operator/","/","ms");
mr_op_sa_mb(f,d,1,"operator/","/","sm");
mr_op_ma_sb(f,1,d,"operator/","/","ms");
ma_op_ma_sb(f,d,d,"operator/=","/=","ms");
ma_op_ma_sb(f,d,1,"operator/=","/=","ms");
ma_op_ma_sb(f,1,d,"operator/=","/=","ms");
mr_convert_to_ma(f,d,d,"m");
mr_convert_to_ma(f,d,1,"m");
mr_convert_to_ma(f,1,d,"m");
bool_eq_ma_mb(f,d,d,"mm");
bool_eq_ma_mb(f,d,1,"mm");
bool_eq_ma_mb(f,1,d,"mm");
bool_neq_ma_mb(f,d,d,"mm");
bool_neq_ma_mb(f,d,1,"mm");
bool_neq_ma_mb(f,1,d,"mm");
mr_op_ma(f,d,d,"operator-","-","m");
mr_op_ma(f,d,1,"operator-","-","m");
mr_op_ma(f,1,d,"operator-","-","m");
determinant(f,d,0);
inverse_ma(f,d,"m");
mr_mult_ma_mb(f,d,d,d,"mm");
ma_mult_ma_mb(f,d,"mm");
mr_mult_ma_mb(f,d,d,1,"mm");
mr_mult_ma_mb(f,1,d,d,"mm");
f.dump("mat_operations"+to_string(d)+".hpp");
}
for( int d=2; d!=5; ++d )
{
output_file f(opt);
ma_assign_ma_mb(f,d,d,"mm");
ma_assign_ma_mb(f,d,1,"mm");
ma_assign_ma_mb(f,1,d,"mm");
f.dump("mat_assign"+to_string(d)+".hpp");
}
for( int d=2; d!=5; ++d )
{
output_file f(opt);
{
char buf[1024];
sprintf(buf,INCLUDE_VEC_ASSIGN,d);
f.require_include(buf);
}
vr_op_va_vb_same_size(f,d,"operator+","+","vv");
vr_op_va_vb_same_size(f,d,"operator-","-","vv");
va_op_va_vb_same_size(f,d,"operator+=","+=","vv");
va_op_va_vb_same_size(f,d,"operator-=","-=","vv");
vr_op_va_sb(f,d,"operator*","*","vs");
vr_op_sa_vb(f,d,"operator*","*","sv");
va_op_va_sb(f,d,"operator*=","*=","vs");
vr_op_va_sb(f,d,"operator/","/","vs");
va_op_va_sb(f,d,"operator/=","/=","vs");
vr_convert_to_va(f,d,"v");
bool_eq_va_vb(f,d,"vv");
bool_neq_va_vb(f,d,"vv");
vr_op_va(f,d,"operator-","-","v");
mag(f,d,"v");
mag_sqr(f,d,"v");
normalize(f,d,"v");
dot(f,d,"vv");
f.dump("vec_operations"+to_string(d)+".hpp");
}
for( int d=2; d!=5; ++d )
{
output_file f(opt);
va_assign_va_vb(f,d,"vv");
f.dump("vec_assign"+to_string(d)+".hpp");
}
for( int d=2; d!=5; ++d )
{
output_file f(opt);
vr_mult_ma_vb(f,d,d,"mv");
vr_mult_va_mb(f,d,d,"vm");
f.dump("vec_mat_operations"+to_string(d)+".hpp");
}
{
output_file f(opt);
swizzle(f,2);
f.dump("swizzle2.hpp");
}
{
output_file f(opt);
swizzle(f,3);
f.dump("swizzle3.hpp");
}
{
output_file f(opt);
swizzle(f,4);
f.dump("swizzle4.hpp");
}
}
}
int
main( int argc, char const * argv[] )
{
try
{
gen(argc,argv);
}
catch(
std::ifstream::failure & )
{
std::cerr << "Failed to write generated output file" << std::endl;
}
catch(
... )
{
std::cerr << "Unexpected exception" << std::endl << boost::current_exception_diagnostic_information();
}
return 1;
}