Skip to content

Instantly share code, notes, and snippets.

@ThePhD
Last active August 29, 2015 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ThePhD/f396fa545fc50097a9f0 to your computer and use it in GitHub Desktop.
Save ThePhD/f396fa545fc50097a9f0 to your computer and use it in GitHub Desktop.
Symbolic Functions
#pragma once
#include <Furrovine++/typetraits.h>
#include <utility>
#include <functional>
namespace Furrovine {
struct symbol_tag {};
template <typename Constant>
struct constant {
typedef symbol_tag symbol_type;
Constant c;
template <typename... Tn>
constant( Tn&&... argn ) : c( std::forward<Tn>( argn )... ) {}
template <typename T>
Constant operator()( T&& ) const {
return c;
}
};
template <typename T = void>
struct variable {
typedef symbol_tag symbol_type;
template <typename T>
T operator()( T&& x ) {
return static_cast<T>( x );
}
};
template <>
struct variable<void> {
typedef symbol_tag symbol_type;
template <typename T>
auto operator()( T&& x ) -> decltype( std::forward<T>( x ) ) {
return std::forward<T>( x );
}
};
template<typename Symbol>
struct symbol {
typedef symbol_tag symbol_type;
Symbol s;
symbol( Symbol s ) : s( std::move( s ) ) {}
template <typename T>
unqualified_t<T> operator()( T&& x ) {
return static_cast<unqualified_t<T>>( s( std::forward<T>( x ) ) );
}
};
template <typename T>
struct symbol <constant<T>> {
typedef constant<T> Symbol;
typedef symbol_tag symbol_type;
Symbol s;
symbol( Symbol s ) : s( std::move( s ) ) {}
template <typename Tx>
unqualified_t<T> operator()( Tx&& x ) {
return s.c;
}
};
template <>
struct symbol <variable<void>> {
typedef variable<void> Symbol;
typedef symbol_tag symbol_type;
Symbol s;
symbol( Symbol s ) : s( std::move( s ) ) {}
template <typename T>
auto operator()( T&& x ) -> decltype( std::forward<T>( x ) ) {
return std::forward<T>( x );
}
};
template <typename T>
struct symbol<variable<T>> {
typedef variable<T> Symbol;
typedef symbol_tag symbol_type;
Symbol s;
symbol( Symbol s ) : s( std::move( s ) ) {}
template <typename Tx>
T operator()( Tx&& x ) {
return s( std::forward<Tx>( x ) );
}
};
template<typename First, typename Second, typename Operator>
struct expression {
private:
First lhs;
Second rhs;
Operator op;
public:
typedef symbol_tag symbol_type;
expression( First lhs, Second rhs, Operator op = Operator( ) ) : lhs( std::move( lhs ) ), rhs( std::move( rhs ) ), op( std::move( op ) ) {}
template <typename T>
auto operator()( T x ) -> decltype( op( lhs( x ), rhs( x ) ) ) {
return op( lhs( x ), rhs( x ) );
}
};
using add = std::plus<>;
using subtract = std::minus<>;
using multiply = std::multiplies<>;
using divide = std::divides<>;
template<typename First, typename Second, typename Operator>
using expression_t = expression < symbol<First>, symbol<Second>, Operator > ;
template<typename T, typename = void>
struct is_symbol_impl : std::false_type {};
template<typename T>
struct is_symbol_impl<T, typename tmp_void_test<typename T::symbol_type>::type> : std::true_type {};
template<typename T>
struct is_symbol : is_symbol_impl<T>{};
// operators..
template<typename First, typename Second, typename R = expression_t<First, Second, add>,
typename std::enable_if<std::integral_constant<bool, is_symbol<First>::value && is_symbol<Second>::value>::value, int>::type = 0>
R operator+( First lhs, Second rhs ) {
return R{ symbol<First>( lhs ), symbol<Second>( rhs ) };
}
template<typename First, typename Second, typename R = expression_t<First, Second, subtract>,
typename std::enable_if<std::integral_constant<bool, is_symbol<First>::value && is_symbol<Second>::value>::value, int>::type = 0>
R operator-( First lhs, Second rhs ) {
return R{ lhs, rhs };
}
template<typename First, typename Second, typename R = expression_t<First, Second, multiply>,
typename std::enable_if<std::integral_constant<bool, is_symbol<First>::value && is_symbol<Second>::value>::value, int>::type = 0>
R operator*( First lhs, Second rhs ) {
return R{ lhs, rhs };
}
template<typename First, typename Second, typename R = expression_t<First, Second, divide>,
typename std::enable_if<std::integral_constant<bool, is_symbol<First>::value && is_symbol<Second>::value>::value, int>::type = 0>
R operator/( First lhs, Second rhs ) {
return R{ lhs, rhs };
}
// constants..
template<typename First, typename Second, typename R = expression_t<First, constant<Second>, add>,
typename std::enable_if<std::integral_constant<bool, is_symbol<First>::value && std::is_arithmetic<Second>::value>::value, int>::type = 0>
R operator+( First lhs, Second rhs ) {
return R{ lhs, constant<Second>(rhs) };
}
template<typename First, typename Second, typename R = expression_t<constant<Second>, First, add>,
typename std::enable_if<std::integral_constant<bool, is_symbol<First>::value && std::is_arithmetic<Second>::value>::value, int>::type = 0>
R operator+( Second lhs, First rhs ) {
return R{ constant<Second>( lhs ), rhs };
}
template<typename First, typename Second, typename R = expression_t<First, constant<Second>, subtract>,
typename std::enable_if<std::integral_constant<bool, is_symbol<First>::value && std::is_arithmetic<Second>::value>::value, int>::type = 0>
R operator-( First lhs, Second rhs ) {
return R{ lhs, constant<Second>( rhs ) };
}
template<typename First, typename Second, typename R = expression_t<constant<Second>, First, subtract>,
typename std::enable_if<std::integral_constant<bool, is_symbol<First>::value && std::is_arithmetic<Second>::value>::value, int>::type = 0>
R operator-( Second lhs, First rhs ) {
return R{ constant<Second>( lhs ), rhs };
}
template<typename First, typename Second, typename R = expression_t<First, constant<Second>, multiply>,
typename std::enable_if<std::integral_constant<bool, is_symbol<First>::value && std::is_arithmetic<Second>::value>::value, int>::type = 0>
R operator*( First lhs, Second rhs ) {
return R{ lhs, constant<Second>( rhs ) };
}
template<typename First, typename Second, typename R = expression_t<constant<Second>, First, multiply>,
typename std::enable_if<std::integral_constant<bool, is_symbol<First>::value && std::is_arithmetic<Second>::value>::value, int>::type = 0>
R operator*( Second lhs, First rhs ) {
return R{ constant<Second>( lhs ), rhs };
}
template<typename First, typename Second, typename R = expression_t<First, constant<Second>, divide>,
typename std::enable_if<std::integral_constant<bool, is_symbol<First>::value && std::is_arithmetic<Second>::value>::value, int>::type = 0>
R operator/( First lhs, Second rhs ) {
return R{ lhs, constant<Second>( rhs ) };
}
template<typename First, typename Second, typename R = expression_t<constant<Second>, First, divide>,
typename std::enable_if<std::integral_constant<bool, is_symbol<First>::value && std::is_arithmetic<Second>::value>::value, int>::type = 0>
R operator/( Second lhs, First rhs ) {
return R{ constant<Second>( lhs ), rhs };
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment