Skip to content

Instantly share code, notes, and snippets.

@nekko1119
Created July 30, 2013 13:00
Show Gist options
  • Save nekko1119/6112683 to your computer and use it in GitHub Desktop.
Save nekko1119/6112683 to your computer and use it in GitHub Desktop.
boost見ながら式テンプレートを用いた数学のベクトル書いてみた。
//ファンクタを適用する式
#ifndef NEK_MATH_EXPRESSION_HPP
#define NEK_MATH_EXPRESSION_HPP
#include <type_traits>//is_same, declval, ...
namespace nek
{
namespace math
{
//ベクトルに対する式
//CRTP使用
template <class Expr>
struct vector_expression
{
typedef Expr expr_type;
//本来の型にキャスト
const expr_type& operator()() const
{
return *static_cast<const expr_type*>(this);
}
expr_type operator()()
{
return *static_cast<expr_type*>(this);
}
};
template<class T>
struct scalar_identity;
//単項演算子の式
template <class T, class F>
class unary_expression
: public vector_expression<unary_expression<T, F>>
{
public:
typedef F function_type;
typedef typename F::result_type value_type;
typedef value_type const_reference;
typedef typename std::conditional<std::is_same<F, scalar_identity<typename T::value_type>>::value,
typename T::reference,
typename value_type>::type reference;
typedef typename T::size_type size_type;
typedef T expr_type;
typedef typename T::const_closure_type expr_closure_type;
typedef unary_expression<T, F> self_type;
typedef const self_type const_closure_type;
typedef self_type closure_type;
explicit unary_expression(expr_type& expr)
: expr_(expr)
{
}
inline const_reference operator[](size_type i) const
{
return function_type::apply(expr_[i]);
}
inline reference operator[](size_type i)
{
return function_type::apply(expr_[i]);
}
private:
expr_closure_type expr_;
};
//二項演算子の式
template <class L, class F, class R>
class binary_expression
: public vector_expression<binary_expression<L, F, R>>
{
public:
typedef F function_type;
typedef typename F::result_type value_type;
typedef value_type const_reference;
typedef decltype(std::declval<typename L::size_type>() + std::declval<typename R::size_type>()) size_type;
typedef L first_expr_type;
typedef R second_expr_type;
typedef typename L::const_closure_type first_closure_type;
typedef typename R::const_closure_type second_closure_type;
typedef binary_expression<L, F, R> self_type;
typedef const self_type const_closure_type;
binary_expression(const first_expr_type& left, const second_expr_type& right)
: left_(left),
right_(right)
{
}
inline const_reference operator[](size_type i) const
{
return function_type::apply(left_[i], right_[i]);
}
private:
first_closure_type left_;
second_closure_type right_;
};
//ただ参照を返すだけの式
template <class Expr>
class vector_reference
: public vector_expression<Expr>
{
public:
typedef vector_reference<Expr> self_type;
typedef typename Expr::size_type size_type;
typedef typename Expr::value_type value_type;
typedef typename Expr::const_reference const_reference;
typedef typename std::conditional<std::is_const<Expr>::value,
typename Expr::const_reference,
typename Expr::reference>::type reference;
typedef Expr referred_type;
typedef const self_type const_closure_type;
typedef self_type closure_type;
explicit vector_reference(referred_type& expr)
: expr_(expr)
{
}
inline const_reference operator[](size_type i) const
{
return expr_[i];
}
inline reference operator[](size_type i)
{
return expr_[i];
}
private:
referred_type expr_;
};
}
}
#endif
//演算を行うファンクタを定義
#ifndef NEK_MATH_FUNCTION_HPP
#define NEK_MATH_FUNCTION_HPP
#include "expression.hpp"
namespace nek
{
namespace math
{
//要素に対する単項ファンクタ基底クラス
template <class T>
struct scalar_unary_function
{
typedef T value_type;
typedef const T& arg_type;
typedef value_type result_type;
};
//要素そのまま
template <class T>
struct scalar_identity
: public scalar_unary_function<T>
{
typedef typename scalar_unary_function<T>::arg_type arg_type;
typedef typename scalar_unary_function<T>::result_type result_type;
static result_type apply(arg_type v)
{
return v;
}
};
//要素の符号を反転
template <class T>
struct scalar_negate
: public scalar_unary_function<T>
{
typedef typename scalar_unary_function<T>::arg_type arg_type;
typedef typename scalar_unary_function<T>::result_type result_type;
static result_type apply(arg_type v)
{
return -v;
}
};
//要素に対する二項ファンクタ基底クラス
template <class L, class R>
struct scalar_binary_function
{
typedef const L& first_type;
typedef const R& second_type;
typedef decltype(std::declval<first_type>() + std::declval<second_type>()) result_type;
};
//要素に対する加算
template <class L, class R>
struct scalar_plus
: public scalar_binary_function<L, R>
{
typedef typename scalar_binary_function<L, R>::first_type first_type;
typedef typename scalar_binary_function<L, R>::second_type second_type;
typedef typename scalar_binary_function<L, R>::result_type result_type;
static result_type apply(first_type l, second_type r)
{
return l + r;
}
};
//要素に対する減算
template <class L, class R>
struct scalar_minus
: public scalar_binary_function<L, R>
{
typedef typename scalar_binary_function<L, R>::first_type first_type;
typedef typename scalar_binary_function<L, R>::second_type second_type;
typedef typename scalar_binary_function<L, R>::result_type result_type;
static result_type apply(first_type l, second_type r)
{
return l - r;
}
};
//要素に対する乗算
template <class L, class R>
struct scalar_multiply
: public scalar_binary_function<L, R>
{
typedef typename scalar_binary_function<L, R>::first_type first_type;
typedef typename scalar_binary_function<L, R>::second_type second_type;
typedef typename scalar_binary_function<L, R>::result_type result_type;
static result_type apply(first_type l, second_type r)
{
return l * r;
}
};
//要素に対する除算
template <class L, class R>
struct scalar_devide
: public scalar_binary_function<L, R>
{
typedef typename scalar_binary_function<L, R>::first_type first_type;
typedef typename scalar_binary_function<L, R>::second_type second_type;
typedef typename scalar_binary_function<L, R>::result_type result_type;
static result_type apply(first_type l, second_type r)
{
return l / r;
}
};
//要素に対する代入ファンクタ基底クラス
template <class L, class R>
struct scalar_binary_assign_funciton
{
typedef typename std::remove_reference<
typename std::remove_const<L>::type
>::type& first_type;
typedef const R& second_type;
};
//要素に対する代入
template <class L, class R>
struct scalar_assign
: public scalar_binary_assign_funciton<L, R>
{
typedef typename scalar_binary_assign_funciton<L, R>::first_type first_type;
typedef typename scalar_binary_assign_funciton<L, R>::second_type second_type;
static void apply(first_type l, second_type r)
{
l = r;
}
};
//要素に対する加算代入
template <class L ,class R>
struct scalar_plus_assign
: public scalar_binary_assign_funciton<L, R>
{
typedef typename scalar_binary_assign_funciton<L, R>::first_type first_type;
typedef typename scalar_binary_assign_funciton<L, R>::second_type second_type;
static void apply(first_type l, second_type r)
{
l += r;
}
};
//要素に対する減算代入
template <class L ,class R>
struct scalar_minus_assign
: public scalar_binary_assign_funciton<L, R>
{
typedef typename scalar_binary_assign_funciton<L, R>::first_type first_type;
typedef typename scalar_binary_assign_funciton<L, R>::second_type second_type;
static void apply(first_type l, second_type r)
{
l -= r;
}
};
//要素に対する乗算代入
template <class L ,class R>
struct scalar_multiply_assign
: public scalar_binary_assign_funciton<L, R>
{
typedef typename scalar_binary_assign_funciton<L, R>::first_type first_type;
typedef typename scalar_binary_assign_funciton<L, R>::second_type second_type;
static void apply(first_type l, second_type r)
{
l *= r;
}
};
//加算記号
template<class L, class R>
binary_expression<L, scalar_plus<typename L::value_type, typename R::value_type>, R>
operator+(const vector_expression<L>& left, const vector_expression<R>& right)
{
typedef binary_expression<L, scalar_plus<typename L::value_type, typename R::value_type>, R> expr_type;
return expr_type(left(), right());
}
//減算記号
template<class L, class R>
binary_expression<L, scalar_minus<typename L::value_type, typename R::value_type>, R>
operator-(const vector_expression<L>& left, const vector_expression<R>& right)
{
typedef binary_expression<L, scalar_minus<typename L::value_type, typename R::value_type>, R> expr_type;
return expr_type(left(), right());
}
//乗算記号
template<class L, class R>
binary_expression<L, scalar_multiply<typename L::value_type, typename R::value_type>, R>
operator*(const vector_expression<L>& left, const vector_expression<R>& right)
{
typedef binary_expression<L, scalar_multiply<typename L::value_type, typename R::value_type>, R> expr_type;
return expr_type(left(), right());
}
//除算記号
template<class L, class R>
binary_expression<L, scalar_devide<typename L::value_type, typename R::value_type>, R>
operator/(const vector_expression<L>& left, const vector_expression<R>& right)
{
typedef binary_expression<L, scalar_devide<typename L::value_type, typename R::value_type>, R> expr_type;
return expr_type(left(), right());
}
}
}
#endif
#include "vector.hpp"
#include <iostream>
int main()
{
typedef nek::math::vector<int, 3> vector;
vector v1;
for(const auto& it : v1)
{
std::cout << it << std::endl;
}
}
//固定長ベクトルクラス
#ifndef NEK_MATH_VECTOR_HPP
#define NEK_MATH_VECTOR_HPP
#include "expression.hpp"
#include "function.hpp"
#include <array>//array
#include <cassert>//assert
#include <initializer_list>//initializer_list
#include <iterator>//iterator random_access_iterator_tag
#include <stdexcept>//invalid_argument
namespace nek
{
namespace math
{
//イテレータ
template <class T, std::size_t N>
class vector_const_iterator
: public std::iterator<std::random_access_iterator_tag, T>
{
public:
typedef vector_const_iterator<T, N> self_type;
typedef std::size_t size_type;
typedef std::iterator<std::random_access_iterator_tag, T> base_type;
typedef typename base_type::iterator_category iterator_category;
typedef typename base_type::value_type value_type;
typedef typename base_type::difference_type difference_type;
typedef const value_type* pointer;
typedef const value_type& reference;
vector_const_iterator(pointer ptr)
: vector_const_iterator(ptr, 0)
{
}
vector_const_iterator(pointer ptr, size_type id)
: ptr_(ptr),
id_(id)
{
}
inline reference operator*() const
{
check_nullptr();
check_over(id_);
return ptr_[id_];
}
inline pointer operator->() const
{
return &**this;
}
inline self_type& operator++()
{
check_over(id_);
++id_;
return *this;
}
inline self_type operator++(int)
{
self_type temp_iter(*this);
++*this;
return temp_iter;
}
inline self_type& operator--()
{
check_under(id);
--id_;
return *this;
}
inline self_type operator--(int)
{
self_type temp_iter(*this);
--*this;
return temp_iter;
}
inline self_type& operator+=(difference_type offset)
{
check_over(id_ + offset);
id_ += offset;
return *this;
}
inline self_type operator+(difference_type offset) const
{
return self_type(*this += offset);
}
inline self_type& operator-=(difference_type offset)
{
return *this += -offset;
}
inline self_type operator-(difference_type offset) const
{
return self_type(*this -= offset);
}
inline reference operator[](difference_type offset) const
{
check_nullptr();
check_over(offset);
return ptr_[offset];
}
inline bool operator==(const self_type& right) const
{
check_compatible(right);
return id_ == right.id_;
}
inline bool operator!=(const self_type& right) const
{
return !(*this == right);
}
inline bool operator<(const self_type& right) const
{
check_compatible(right);
return id_ < right.id_;
}
inline bool operator>(const self_type& right) const
{
return right_ < *this;
}
inline bool operator<=(const self_type& right) const
{
return !(right_ < *this);
}
inline bool operator>=(const self_type& right) const
{
return !(*this < right);
}
private:
void check_nullptr() const
{
assert(ptr_ != nullptr);
}
void check_over(difference_type off) const
{
assert(off < N);
}
void check_under(difference_type off) const
{
assert(0 <= off);
}
void check_compatible(const self_type& right) const
{
assert(ptr_ == right.ptr_);
}
pointer ptr_;
size_type id_;
};
template <class T, std::size_t N>
class vector_iterator
: public std::iterator<std::random_access_iterator_tag, T>
{
public:
typedef vector_iterator<T, N> self_type;
typedef std::size_t size_type;
typedef std::iterator<std::random_access_iterator_tag, T> base_type;
typedef typename base_type::iterator_category iterator_category;
typedef typename base_type::value_type value_type;
typedef typename base_type::difference_type difference_type;
typedef typename base_type::pointer pointer;
typedef typename base_type::reference reference;
vector_iterator(pointer ptr)
: vector_iterator(ptr, 0)
{
}
vector_iterator(pointer ptr, size_type id)
: iter_(ptr, id)
{
}
inline reference operator*() const
{
return const_cast<reference>(*iter_);
}
inline pointer operator->() const
{
return const_cast<pointer>(&*iter_);
}
inline self_type& operator++()
{
++iter_;
return *this;
}
inline self_type operator++(int)
{
self_type temp_iter(*this);
++*this;
return temp_iter;
}
inline self_type& operator--()
{
--iter_;
return *this;
}
inline self_type operator--(int)
{
self_type temp_iter(*this);
--*this;
return temp_iter;
}
inline self_type& operator+=(difference_type offset)
{
iter_ += offset;
return *this;
}
inline self_type operator+(difference_type offset) const
{
return self_type(*this += offset);
}
inline self_type& operator-=(difference_type offset)
{
return *this += -offset;
}
inline self_type operator-(difference_type offset) const
{
return self_type(*this -= offset);
}
inline reference operator[](difference_type offset) const
{
return iter_.[offset];
}
inline bool operator==(const self_type& right) const
{
return iter_ == right.iter_;
}
inline bool operator!=(const self_type& right) const
{
return !(*this == right);
}
inline bool operator<(const self_type& right) const
{
return iter_ < right.iter_;
}
inline bool operator>(const self_type& right) const
{
return right_ < *this;
}
inline bool operator<=(const self_type& right) const
{
return !(right_ < *this);
}
inline bool operator>=(const self_type& right) const
{
return !(*this < right);
}
private:
vector_const_iterator<T, N> iter_;
};
//固定長ベクトル
template <class T, std::size_t N>
class vector
: public vector_expression<vector<T, N>>
{
public:
typedef vector<T, N> self_type;
typedef const vector_reference<const self_type> const_closure_type;
typedef vector_reference<self_type> closure_type;
typedef std::array<T, N> array_type;
typedef typename array_type::value_type value_type;
typedef typename array_type::size_type size_type;
typedef typename array_type::difference_type difference_type;
typedef typename array_type::pointer pointer;
typedef typename array_type::const_pointer const_pointer;
typedef typename array_type::reference reference;
typedef typename array_type::const_reference const_reference;
typedef vector_const_iterator<T, N> const_iterator;
typedef vector_iterator<T, N> iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef value_type expr_type;
vector()
{
}
vector(const T& val)
{
data_.assign(val);
}
vector(std::initializer_list<T> list)
{
if(N < list.size())
{
throw std::invalid_argument("vector<T, N>::vector : initializer list size must be under N");
}
std::copy(list.begin(), list.end(), data_.begin());
}
template <class Expr>
vector(const vector_expression<Expr>& expr)
{
assign<scalar_assign>(expr);
}
vector(const vector& right)
: data_(right.data_)
{
}
vector& operator=(vector right)
{
swap(right);
return *this;
}
template <class Expr>
vector& operator=(const vector_expression<Expr>& expr)
{
self_type temp(expr);
swap(temp);
return *this;
}
inline const_reference operator[](size_type i) const
{
return data_[i];
}
inline reference operator[](size_type i)
{
return data_[i];
}
inline const_reference at(size_type i) const
{
return data_.at(i);
}
inline reference at(size_type i)
{
return data_.at(i);
}
inline size_type size() const
{
return data_.size();
}
inline bool empty() const
{
return data_.empty();
}
inline void swap(vector& right) throw()
{
using std::swap;
swap(data_, right.data_);
}
inline const_pointer data() const
{
return data_.data();
}
inline pointer data()
{
return data_.data();
}
inline iterator begin() throw()
{
return iterator(std::addressof(data_[0]), 0);
}
inline const_iterator begin() const throw()
{
return const_iterator(std::addressof(data_[0]), 0);
}
inline iterator end() throw()
{
return iterator(std::addressof(data_[0]), N);
}
inline const_iterator end() const throw()
{
return const_iterator(std::addressof(data_[0]), N);
}
inline reverse_iterator rbegin() throw()
{
return reverse_iterator(end());
}
inline const_reverse_iterator rbegin() const throw()
{
return const_reverse_iterator(end());
}
inline reverse_iterator rend() throw()
{
return reverse_iterator(begin());
}
inline const_reverse_iterator rend() const throw()
{
return const_reverse_iterator(begin());
}
inline const_iterator cbegin() const throw()
{
return static_cast<const_pointer>(this)->begin();
}
inline const_iterator cend() const throw()
{
return static_cast<const_pointer>(this)->end();
}
inline const_reverse_iterator crbegin() const throw()
{
return static_cast<const_pointer>(this)->rbegin();
}
inline const_iterator crend() const throw()
{
return static_cast<const_pointer>(this)->rend();
}
template <class Expr>
vector& operator+=(const vector_expression<Expr>& expr)
{
self_type temp(*this + expr);
swap(temp);
return *this;
}
template <class Expr>
vector& plus_assign(const vector_expression<Expr>& expr)
{
assign<scalar_plus_assign>(expr);
return *this;
}
template <class Expr>
vector& operator-=(const vector_expression<Expr>& expr)
{
self_type temp(*this - expr);
swap(temp);
return *this;
}
template <class Expr>
vector& minus_assign(const vector_expression<Expr>& expr)
{
assign<scalar_minus_assign>(expr);
return *this;
}
template <class Expr>
vector& operator*=(const vector_expression<Expr>& expr)
{
self_type temp(*this * expr);
swap(temp);
return *this;
}
template <class Expr>
vector& multiply_assign(const vector_expression<Expr>& expr)
{
assign<scalar_multiply_assign>(expr);
return *this;
}
template <class Expr>
vector& operator/=(const vector_expression<Expr>& expr)
{
self_type temp(*this / expr);
swap(temp);
return *this;
}
template <class Expr>
vector& devide_assign(const vector_expression<Expr>& expr)
{
assign<scalar_devide_assign>(expr);
return *this;
}
private:
template <template <class, class> class F, class E>
inline void assign(const vector_expression<E>& expr)
{
typedef F<reference, typename E::value_type> functor_type;
size_type last = data_.size();
for(size_type i = 0; i < last; ++i)
{
functor_type::apply(data_[i], expr()[i]);
}
}
array_type data_;
};
template <std::size_t I, class T, std::size_t N>
T& get(vector<T, N>& v) throw()
{
static_assert(0 <= I && I < N, "math::get<I, T, N> : out of range");
return v[I];
}
template <std::size_t I, class T, std::size_t N>
const T& get(const vector<T, N>& v) throw()
{
static_assert(0 <= I && I < N, "math::get<I, T, N> : out of range");
return v[I];
}
template <std::size_t I, class T, std::size_t N>
T&& get(vector<T, N>&& v) throw()
{
static_assert(0 <= I && I < N, "math::get<I, T, N> : out of range");
return std::forward<T&&>(v[I]);
}
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment