-
-
Save ThePhD/f396fa545fc50097a9f0 to your computer and use it in GitHub Desktop.
Symbolic Functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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