arkpar
10 years ago
54 changed files with 1836 additions and 404 deletions
@ -0,0 +1,520 @@ |
|||
|
|||
// This is a copy of boost/multiprecision/detail/number_compare.hpp from boost 1.59 to replace buggy version from 1.58.
|
|||
|
|||
#ifdef BOOST_MP_COMPARE_HPP |
|||
#error This bug workaround header must be included before original boost/multiprecision/detail/number_compare.hpp |
|||
#endif |
|||
|
|||
///////////////////////////////////////////////////////////////////////////////
|
|||
// Copyright 2012 John Maddock. 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)
|
|||
|
|||
#ifndef BOOST_MP_COMPARE_HPP |
|||
#define BOOST_MP_COMPARE_HPP |
|||
|
|||
// A copy of boost/multiprecision/traits/is_backend.hpp
|
|||
#ifndef BOOST_MP_IS_BACKEND_HPP |
|||
#define BOOST_MP_IS_BACKEND_HPP |
|||
|
|||
#include <boost/mpl/has_xxx.hpp> |
|||
#include <boost/type_traits/conditional.hpp> |
|||
#include <boost/type_traits/is_convertible.hpp> |
|||
#include <boost/multiprecision/detail/number_base.hpp> |
|||
#include <boost/multiprecision/detail/generic_interconvert.hpp> |
|||
|
|||
namespace boost{ namespace multiprecision{ namespace detail{ |
|||
|
|||
BOOST_MPL_HAS_XXX_TRAIT_DEF(signed_types) |
|||
BOOST_MPL_HAS_XXX_TRAIT_DEF(unsigned_types) |
|||
BOOST_MPL_HAS_XXX_TRAIT_DEF(float_types) |
|||
|
|||
template <class T> |
|||
struct is_backend |
|||
{ |
|||
static const bool value = has_signed_types<T>::value && has_unsigned_types<T>::value && has_float_types<T>::value; |
|||
}; |
|||
|
|||
template <class Backend> |
|||
struct other_backend |
|||
{ |
|||
typedef typename boost::conditional< |
|||
boost::is_same<number<Backend>, number<Backend, et_on> >::value, |
|||
number<Backend, et_off>, number<Backend, et_on> >::type type; |
|||
}; |
|||
|
|||
template <class B, class V> |
|||
struct number_from_backend |
|||
{ |
|||
typedef typename boost::conditional < |
|||
boost::is_convertible<V, number<B> >::value, |
|||
number<B>, |
|||
typename other_backend<B>::type > ::type type; |
|||
}; |
|||
|
|||
template <bool b, class T, class U> |
|||
struct is_first_backend_imp{ static const bool value = false; }; |
|||
template <class T, class U> |
|||
struct is_first_backend_imp<true, T, U>{ static const bool value = is_convertible<U, number<T, et_on> >::value || is_convertible<U, number<T, et_off> >::value; }; |
|||
|
|||
template <class T, class U> |
|||
struct is_first_backend : is_first_backend_imp<is_backend<T>::value, T, U> {}; |
|||
|
|||
template <bool b, class T, class U> |
|||
struct is_second_backend_imp{ static const bool value = false; }; |
|||
template <class T, class U> |
|||
struct is_second_backend_imp<true, T, U>{ static const bool value = is_convertible<T, number<U> >::value || is_convertible<T, number<U, et_off> >::value; }; |
|||
|
|||
template <class T, class U> |
|||
struct is_second_backend : is_second_backend_imp<is_backend<U>::value, T, U> {}; |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
#endif // BOOST_MP_IS_BACKEND_HPP
|
|||
|
|||
//
|
|||
// Comparison operators for number.
|
|||
//
|
|||
|
|||
namespace boost{ namespace multiprecision{ |
|||
|
|||
namespace default_ops{ |
|||
|
|||
template <class B> |
|||
inline bool eval_eq(const B& a, const B& b) |
|||
{ |
|||
return a.compare(b) == 0; |
|||
} |
|||
template <class T, class U> |
|||
inline typename enable_if_c<boost::multiprecision::detail::is_first_backend<T, U>::value, bool>::type eval_eq(const T& a, const U& b) |
|||
{ |
|||
typename boost::multiprecision::detail::number_from_backend<T, U>::type t(b); |
|||
return eval_eq(a, t.backend()); |
|||
} |
|||
template <class T, class U> |
|||
inline typename enable_if_c<boost::multiprecision::detail::is_second_backend<T, U>::value, bool>::type eval_eq(const T& a, const U& b) |
|||
{ |
|||
typename boost::multiprecision::detail::number_from_backend<U, T>::type t(a); |
|||
return eval_eq(t.backend(), b); |
|||
} |
|||
|
|||
template <class B> |
|||
inline bool eval_lt(const B& a, const B& b) |
|||
{ |
|||
return a.compare(b) < 0; |
|||
} |
|||
template <class T, class U> |
|||
inline typename enable_if_c<boost::multiprecision::detail::is_first_backend<T, U>::value, bool>::type eval_lt(const T& a, const U& b) |
|||
{ |
|||
typename boost::multiprecision::detail::number_from_backend<T, U>::type t(b); |
|||
return eval_lt(a, t.backend()); |
|||
} |
|||
template <class T, class U> |
|||
inline typename enable_if_c<boost::multiprecision::detail::is_second_backend<T, U>::value, bool>::type eval_lt(const T& a, const U& b) |
|||
{ |
|||
typename boost::multiprecision::detail::number_from_backend<U, T>::type t(a); |
|||
return eval_lt(t.backend(), b); |
|||
} |
|||
|
|||
template <class B> |
|||
inline bool eval_gt(const B& a, const B& b) |
|||
{ |
|||
return a.compare(b) > 0; |
|||
} |
|||
template <class T, class U> |
|||
inline typename enable_if_c<boost::multiprecision::detail::is_first_backend<T, U>::value, bool>::type eval_gt(const T& a, const U& b) |
|||
{ |
|||
typename boost::multiprecision::detail::number_from_backend<T, U>::type t(b); |
|||
return eval_gt(a, t.backend()); |
|||
} |
|||
template <class T, class U> |
|||
inline typename enable_if_c<boost::multiprecision::detail::is_second_backend<T, U>::value, bool>::type eval_gt(const T& a, const U& b) |
|||
{ |
|||
typename boost::multiprecision::detail::number_from_backend<U, T>::type t(a); |
|||
return eval_gt(t.backend(), b); |
|||
} |
|||
|
|||
} // namespace default_ops
|
|||
|
|||
namespace detail{ |
|||
|
|||
template <class Num, class Val> |
|||
struct is_valid_mixed_compare : public mpl::false_ {}; |
|||
|
|||
template <class B, expression_template_option ET, class Val> |
|||
struct is_valid_mixed_compare<number<B, ET>, Val> : public is_convertible<Val, number<B, ET> > {}; |
|||
|
|||
template <class B, expression_template_option ET> |
|||
struct is_valid_mixed_compare<number<B, ET>, number<B, ET> > : public mpl::false_ {}; |
|||
|
|||
template <class B, expression_template_option ET, class tag, class Arg1, class Arg2, class Arg3, class Arg4> |
|||
struct is_valid_mixed_compare<number<B, ET>, expression<tag, Arg1, Arg2, Arg3, Arg4> > |
|||
: public mpl::bool_<is_convertible<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >::value> {}; |
|||
|
|||
template <class tag, class Arg1, class Arg2, class Arg3, class Arg4, class B, expression_template_option ET> |
|||
struct is_valid_mixed_compare<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> > |
|||
: public mpl::bool_<is_convertible<expression<tag, Arg1, Arg2, Arg3, Arg4>, number<B, ET> >::value> {}; |
|||
|
|||
template <class Backend, expression_template_option ExpressionTemplates> |
|||
inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Backend>::value != number_kind_floating_point, bool>::type is_unordered_value(const number<Backend, ExpressionTemplates>&) |
|||
{ |
|||
return false; |
|||
} |
|||
template <class Backend, expression_template_option ExpressionTemplates> |
|||
inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Backend>::value == number_kind_floating_point, bool>::type is_unordered_value(const number<Backend, ExpressionTemplates>& a) |
|||
{ |
|||
using default_ops::eval_fpclassify; |
|||
return eval_fpclassify(a.backend()) == FP_NAN; |
|||
} |
|||
|
|||
template <class Arithmetic> |
|||
inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Arithmetic>::value != number_kind_floating_point, bool>::type is_unordered_value(const Arithmetic&) |
|||
{ |
|||
return false; |
|||
} |
|||
template <class Arithmetic> |
|||
inline BOOST_CONSTEXPR typename boost::enable_if_c<number_category<Arithmetic>::value == number_kind_floating_point, bool>::type is_unordered_value(const Arithmetic& a) |
|||
{ |
|||
return (boost::math::isnan)(a); |
|||
} |
|||
|
|||
template <class T, class U> |
|||
inline BOOST_CONSTEXPR bool is_unordered_comparison(const T& a, const U& b) |
|||
{ |
|||
return is_unordered_value(a) || is_unordered_value(b); |
|||
} |
|||
|
|||
} |
|||
|
|||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2> |
|||
inline bool operator == (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) |
|||
{ |
|||
using default_ops::eval_eq; |
|||
if(detail::is_unordered_comparison(a, b)) return false; |
|||
return eval_eq(a.backend(), b.backend()); |
|||
} |
|||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type |
|||
operator == (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) |
|||
{ |
|||
using default_ops::eval_eq; |
|||
if(detail::is_unordered_comparison(a, b)) return false; |
|||
return eval_eq(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b)); |
|||
} |
|||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type |
|||
operator == (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) |
|||
{ |
|||
using default_ops::eval_eq; |
|||
if(detail::is_unordered_comparison(a, b)) return false; |
|||
return eval_eq(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a)); |
|||
} |
|||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type |
|||
operator == (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) |
|||
{ |
|||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; |
|||
using default_ops::eval_eq; |
|||
result_type t(b); |
|||
if(detail::is_unordered_comparison(a, t)) return false; |
|||
return eval_eq(t.backend(), result_type::canonical_value(a)); |
|||
} |
|||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type |
|||
operator == (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) |
|||
{ |
|||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; |
|||
using default_ops::eval_eq; |
|||
result_type t(a); |
|||
if(detail::is_unordered_comparison(t, b)) return false; |
|||
return eval_eq(t.backend(), result_type::canonical_value(b)); |
|||
} |
|||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> |
|||
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type |
|||
operator == (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) |
|||
{ |
|||
using default_ops::eval_eq; |
|||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a); |
|||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b); |
|||
if(detail::is_unordered_comparison(t, t2)) return false; |
|||
return eval_eq(t.backend(), t2.backend()); |
|||
} |
|||
|
|||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2> |
|||
inline bool operator != (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) |
|||
{ |
|||
using default_ops::eval_eq; |
|||
if(detail::is_unordered_comparison(a, b)) return true; |
|||
return !eval_eq(a.backend(), b.backend()); |
|||
} |
|||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type |
|||
operator != (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) |
|||
{ |
|||
using default_ops::eval_eq; |
|||
if(detail::is_unordered_comparison(a, b)) return true; |
|||
return !eval_eq(a.backend(), number<Backend, et_on>::canonical_value(b)); |
|||
} |
|||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type |
|||
operator != (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) |
|||
{ |
|||
using default_ops::eval_eq; |
|||
if(detail::is_unordered_comparison(a, b)) return true; |
|||
return !eval_eq(b.backend(), number<Backend, et_on>::canonical_value(a)); |
|||
} |
|||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type |
|||
operator != (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) |
|||
{ |
|||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; |
|||
using default_ops::eval_eq; |
|||
result_type t(b); |
|||
if(detail::is_unordered_comparison(a, t)) return true; |
|||
return !eval_eq(t.backend(), result_type::canonical_value(a)); |
|||
} |
|||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type |
|||
operator != (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) |
|||
{ |
|||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; |
|||
using default_ops::eval_eq; |
|||
result_type t(a); |
|||
if(detail::is_unordered_comparison(t, b)) return true; |
|||
return !eval_eq(t.backend(), result_type::canonical_value(b)); |
|||
} |
|||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> |
|||
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type |
|||
operator != (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) |
|||
{ |
|||
using default_ops::eval_eq; |
|||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a); |
|||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b); |
|||
if(detail::is_unordered_comparison(t, t2)) return true; |
|||
return !eval_eq(t.backend(), t2.backend()); |
|||
} |
|||
|
|||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2> |
|||
inline bool operator < (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) |
|||
{ |
|||
using default_ops::eval_lt; |
|||
if(detail::is_unordered_comparison(a, b)) return false; |
|||
return eval_lt(a.backend(), b.backend()); |
|||
} |
|||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type |
|||
operator < (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) |
|||
{ |
|||
using default_ops::eval_lt; |
|||
if(detail::is_unordered_comparison(a, b)) return false; |
|||
return eval_lt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b)); |
|||
} |
|||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type |
|||
operator < (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) |
|||
{ |
|||
using default_ops::eval_gt; |
|||
if(detail::is_unordered_comparison(a, b)) return false; |
|||
return eval_gt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a)); |
|||
} |
|||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type |
|||
operator < (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) |
|||
{ |
|||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; |
|||
using default_ops::eval_gt; |
|||
result_type t(b); |
|||
if(detail::is_unordered_comparison(a, t)) return false; |
|||
return eval_gt(t.backend(), result_type::canonical_value(a)); |
|||
} |
|||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type |
|||
operator < (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) |
|||
{ |
|||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; |
|||
using default_ops::eval_lt; |
|||
result_type t(a); |
|||
if(detail::is_unordered_comparison(t, b)) return false; |
|||
return eval_lt(t.backend(), result_type::canonical_value(b)); |
|||
} |
|||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> |
|||
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type |
|||
operator < (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) |
|||
{ |
|||
using default_ops::eval_lt; |
|||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a); |
|||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b); |
|||
if(detail::is_unordered_comparison(t, t2)) return false; |
|||
return eval_lt(t.backend(), t2.backend()); |
|||
} |
|||
|
|||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2> |
|||
inline bool operator > (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) |
|||
{ |
|||
using default_ops::eval_gt; |
|||
if(detail::is_unordered_comparison(a, b)) return false; |
|||
return eval_gt(a.backend(), b.backend()); |
|||
} |
|||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type |
|||
operator > (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) |
|||
{ |
|||
using default_ops::eval_gt; |
|||
if(detail::is_unordered_comparison(a, b)) return false; |
|||
return eval_gt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b)); |
|||
} |
|||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type |
|||
operator > (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) |
|||
{ |
|||
using default_ops::eval_lt; |
|||
if(detail::is_unordered_comparison(a, b)) return false; |
|||
return eval_lt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a)); |
|||
} |
|||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type |
|||
operator > (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) |
|||
{ |
|||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; |
|||
using default_ops::eval_lt; |
|||
result_type t(b); |
|||
if(detail::is_unordered_comparison(a, t)) return false; |
|||
return a > t; |
|||
} |
|||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type |
|||
operator > (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) |
|||
{ |
|||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; |
|||
using default_ops::eval_gt; |
|||
result_type t(a); |
|||
if(detail::is_unordered_comparison(t, b)) return false; |
|||
return t > b; |
|||
} |
|||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> |
|||
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type |
|||
operator > (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) |
|||
{ |
|||
using default_ops::eval_gt; |
|||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a); |
|||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b); |
|||
if(detail::is_unordered_comparison(t, t2)) return false; |
|||
return t > t2; |
|||
} |
|||
|
|||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2> |
|||
inline bool operator <= (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) |
|||
{ |
|||
using default_ops::eval_gt; |
|||
if(detail::is_unordered_comparison(a, b)) return false; |
|||
return !eval_gt(a.backend(), b.backend()); |
|||
} |
|||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type |
|||
operator <= (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) |
|||
{ |
|||
using default_ops::eval_gt; |
|||
if(detail::is_unordered_comparison(a, b)) return false; |
|||
return !eval_gt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b)); |
|||
} |
|||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type |
|||
operator <= (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) |
|||
{ |
|||
using default_ops::eval_lt; |
|||
if(detail::is_unordered_comparison(a, b)) return false; |
|||
return !eval_lt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a)); |
|||
} |
|||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type |
|||
operator <= (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) |
|||
{ |
|||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; |
|||
using default_ops::eval_lt; |
|||
if(detail::is_unordered_value(a) || detail::is_unordered_value(b)) |
|||
return false; |
|||
result_type t(b); |
|||
if(detail::is_unordered_comparison(a, t)) return false; |
|||
return !eval_lt(t.backend(), result_type::canonical_value(a)); |
|||
} |
|||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type |
|||
operator <= (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) |
|||
{ |
|||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; |
|||
using default_ops::eval_gt; |
|||
result_type t(a); |
|||
if(detail::is_unordered_comparison(t, b)) return false; |
|||
return !eval_gt(t.backend(), result_type::canonical_value(b)); |
|||
} |
|||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> |
|||
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type |
|||
operator <= (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) |
|||
{ |
|||
using default_ops::eval_gt; |
|||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a); |
|||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b); |
|||
if(detail::is_unordered_comparison(t, t2)) return false; |
|||
return !eval_gt(t.backend(), t2.backend()); |
|||
} |
|||
|
|||
template <class Backend, expression_template_option ExpressionTemplates, class Backend2, expression_template_option ExpressionTemplates2> |
|||
inline bool operator >= (const number<Backend, ExpressionTemplates>& a, const number<Backend2, ExpressionTemplates2>& b) |
|||
{ |
|||
using default_ops::eval_lt; |
|||
if(detail::is_unordered_comparison(a, b)) return false; |
|||
return !eval_lt(a.backend(), b.backend()); |
|||
} |
|||
template <class Backend, expression_template_option ExpressionTemplates, class Arithmetic> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type |
|||
operator >= (const number<Backend, ExpressionTemplates>& a, const Arithmetic& b) |
|||
{ |
|||
using default_ops::eval_lt; |
|||
if(detail::is_unordered_comparison(a, b)) return false; |
|||
return !eval_lt(a.backend(), number<Backend, ExpressionTemplates>::canonical_value(b)); |
|||
} |
|||
template <class Arithmetic, class Backend, expression_template_option ExpressionTemplates> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<number<Backend, ExpressionTemplates>, Arithmetic>::value, bool>::type |
|||
operator >= (const Arithmetic& a, const number<Backend, ExpressionTemplates>& b) |
|||
{ |
|||
using default_ops::eval_gt; |
|||
if(detail::is_unordered_comparison(a, b)) return false; |
|||
return !eval_gt(b.backend(), number<Backend, ExpressionTemplates>::canonical_value(a)); |
|||
} |
|||
template <class Arithmetic, class Tag, class A1, class A2, class A3, class A4> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type |
|||
operator >= (const Arithmetic& a, const detail::expression<Tag, A1, A2, A3, A4>& b) |
|||
{ |
|||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; |
|||
using default_ops::eval_gt; |
|||
result_type t(b); |
|||
if(detail::is_unordered_comparison(a, t)) return false; |
|||
return !eval_gt(t.backend(), result_type::canonical_value(a)); |
|||
} |
|||
template <class Tag, class A1, class A2, class A3, class A4, class Arithmetic> |
|||
inline typename enable_if_c<detail::is_valid_mixed_compare<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, Arithmetic>::value, bool>::type |
|||
operator >= (const detail::expression<Tag, A1, A2, A3, A4>& a, const Arithmetic& b) |
|||
{ |
|||
typedef typename detail::expression<Tag, A1, A2, A3, A4>::result_type result_type; |
|||
using default_ops::eval_lt; |
|||
result_type t(a); |
|||
if(detail::is_unordered_comparison(t, b)) return false; |
|||
return !eval_lt(t.backend(), result_type::canonical_value(b)); |
|||
} |
|||
template <class Tag, class A1, class A2, class A3, class A4, class Tagb, class A1b, class A2b, class A3b, class A4b> |
|||
inline typename enable_if<is_same<typename detail::expression<Tag, A1, A2, A3, A4>::result_type, typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type>, bool>::type |
|||
operator >= (const detail::expression<Tag, A1, A2, A3, A4>& a, const detail::expression<Tagb, A1b, A2b, A3b, A4b>& b) |
|||
{ |
|||
using default_ops::eval_lt; |
|||
typename detail::expression<Tag, A1, A2, A3, A4>::result_type t(a); |
|||
typename detail::expression<Tagb, A1b, A2b, A3b, A4b>::result_type t2(b); |
|||
if(detail::is_unordered_comparison(t, t2)) return false; |
|||
return !eval_lt(t.backend(), t2.backend()); |
|||
} |
|||
|
|||
|
|||
}} // namespaces
|
|||
|
|||
#endif // BOOST_MP_COMPARE_HPP
|
@ -0,0 +1,125 @@ |
|||
Qt.include("QEtherHelper.js") |
|||
|
|||
var nbRegEx = new RegExp('^[0-9]+$'); |
|||
function validate(model, values) |
|||
{ |
|||
var inError = []; |
|||
for (var k in model) |
|||
{ |
|||
if (values[model[k].name]) |
|||
{ |
|||
var type = model[k].type.name; |
|||
var res; |
|||
if (isContractType(type)) |
|||
res = validateAddress(type, values[model[k].name]); |
|||
else if (type.indexOf("int") !== -1) |
|||
res = validateInt(type, values[model[k].name]); |
|||
else if (type.indexOf("bytes") !== -1) |
|||
res = validateBytes(type, values[model[k].name]); |
|||
else if (type.indexOf("bool") !== -1) |
|||
res = validateBool(type, values[model[k].name]); |
|||
else if (type.indexOf("address") !== -1) |
|||
res = validateAddress(type, values[model[k].name]); |
|||
else |
|||
res.valid = true; |
|||
if (!res.valid) |
|||
inError.push({ type: type, value: values, message: res.message }); |
|||
} |
|||
} |
|||
return inError; |
|||
} |
|||
|
|||
function isContractType(_type) |
|||
{ |
|||
for (var k in Object.keys(codeModel.contracts)) |
|||
{ |
|||
if ("contract " + Object.keys(codeModel.contracts)[k] === _type) |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
function validateInt(_type, _value) |
|||
{ |
|||
var ret = { valid: true, message: "" } |
|||
if (_value.indexOf("-") === 0) |
|||
{ |
|||
_value = _value.substring(1); |
|||
if (_type.indexOf("uint") === -1) |
|||
{ |
|||
ret.valid = false; |
|||
ret.message = "uint type cannot represent negative number"; |
|||
} |
|||
} |
|||
ret.valid = nbRegEx.test(_value); |
|||
if (!ret.valid) |
|||
ret.message = _value + " does not represent " + _type + " type."; |
|||
else |
|||
{ |
|||
var bigInt = createBigInt(_value); |
|||
bigInt.setBigInt(_value); |
|||
var result = bigInt.checkAgainst(_type); |
|||
if (!result.valid) |
|||
{ |
|||
ret.valid = false; |
|||
ret.message = _type + " should be between " + result.minValue + " and " + result.maxValue; |
|||
} |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
function validateAddress(_type, _value) |
|||
{ |
|||
var ret = { valid: true, message: "" } |
|||
if (_value.indexOf("<") === 0 && _value.indexOf(">") === _value.length - 1) |
|||
{ |
|||
var v = _value.split(' - '); |
|||
if (v.length !== 2 || !nbRegEx.test(v[1].replace(">", ""))) // <Contract - 2>
|
|||
{ |
|||
ret.valid = false; |
|||
ret.message = _value + " is not a valid token for address type."; |
|||
} |
|||
} |
|||
else if (_value.indexOf("0x") !== 0) |
|||
{ |
|||
ret.valid = false |
|||
ret.message = "Address type should start with 0x."; |
|||
} |
|||
else |
|||
{ |
|||
_value = _value.substring(2); |
|||
if (_value.length !== 40) |
|||
{ |
|||
ret.valid = false |
|||
ret.message = "Address type should contain 40 characters."; |
|||
} |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
function validateBytes(_type, _value) |
|||
{ |
|||
var ret = { valid: true, message: "" } |
|||
if (_value.length > parseInt(_type.replace("bytes", "")) ) |
|||
{ |
|||
ret.valid = false; |
|||
ret.message = _type + " should not contains more than " + _type.replace("bytes", "") + " characters"; |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
function validateBool(_type, _value) |
|||
{ |
|||
var ret = { valid: true, message: "" } |
|||
if (_value !== "1" && _value !== "0") |
|||
{ |
|||
ret.valid = false; |
|||
ret.message = _value + " is not in the correct bool format"; |
|||
} |
|||
return ret; |
|||
} |
|||
|
|||
function validateEnum(_type, _value) |
|||
{ |
|||
} |
|||
|
@ -0,0 +1,5 @@ |
|||
cmake_policy(SET CMP0015 NEW) |
|||
|
|||
aux_source_directory(. SRCS) |
|||
|
|||
add_sources(${SRCS}) |
@ -0,0 +1,37 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file boost.cpp
|
|||
* @author Lefteris Karapetsas <lefteris@ethdev.com> |
|||
* @date 2015 |
|||
* Tests for external dependencies: Boost |
|||
*/ |
|||
|
|||
#include <boost/test/unit_test.hpp> |
|||
#include <libdevcore/Common.h> |
|||
|
|||
BOOST_AUTO_TEST_SUITE(ExtDepBoost) |
|||
|
|||
// test that reproduces issue https://github.com/ethereum/cpp-ethereum/issues/1977
|
|||
BOOST_AUTO_TEST_CASE(u256_overflow_test) |
|||
{ |
|||
dev::u256 a = 14; |
|||
dev::bigint b = dev::bigint("115792089237316195423570985008687907853269984665640564039457584007913129639948"); |
|||
// to fix cast `a` to dev::bigint
|
|||
BOOST_CHECK(a < b); |
|||
} |
|||
|
|||
BOOST_AUTO_TEST_SUITE_END() |
@ -0,0 +1,224 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file fuzzHelper.cpp
|
|||
* @author Dimitry Khokhlov <winsvega@mail.ru> |
|||
* @date 2015 |
|||
*/ |
|||
|
|||
#include "fuzzHelper.h" |
|||
|
|||
#include <chrono> |
|||
#include <boost/random.hpp> |
|||
#include <boost/filesystem/path.hpp> |
|||
#include <libevmcore/Instruction.h> |
|||
|
|||
namespace dev |
|||
{ |
|||
namespace test |
|||
{ |
|||
|
|||
boost::random::mt19937 RandomCode::gen; |
|||
boostIntDistrib RandomCode::opCodeDist = boostIntDistrib (0, 255); |
|||
boostIntDistrib RandomCode::opLengDist = boostIntDistrib (1, 32); |
|||
boostIntDistrib RandomCode::uniIntDist = boostIntDistrib (0, 0x7fffffff); |
|||
|
|||
boostIntGenerator RandomCode::randOpCodeGen = boostIntGenerator(gen, opCodeDist); |
|||
boostIntGenerator RandomCode::randOpLengGen = boostIntGenerator(gen, opLengDist); |
|||
boostIntGenerator RandomCode::randUniIntGen = boostIntGenerator(gen, uniIntDist); |
|||
|
|||
std::string RandomCode::rndByteSequence(int _length, SizeStrictness _sizeType) |
|||
{ |
|||
refreshSeed(); |
|||
std::string hash; |
|||
_length = (_sizeType == SizeStrictness::Strict) ? std::max(1, _length) : randomUniInt() % _length; |
|||
for (auto i = 0; i < _length; i++) |
|||
{ |
|||
uint8_t byte = randOpCodeGen(); |
|||
hash += toCompactHex(byte); |
|||
} |
|||
return hash; |
|||
} |
|||
|
|||
//generate smart random code
|
|||
std::string RandomCode::generate(int _maxOpNumber, RandomCodeOptions _options) |
|||
{ |
|||
refreshSeed(); |
|||
std::string code; |
|||
|
|||
//random opCode amount
|
|||
boostIntDistrib sizeDist (0, _maxOpNumber); |
|||
boostIntGenerator rndSizeGen(gen, sizeDist); |
|||
int size = (int)rndSizeGen(); |
|||
|
|||
boostWeightGenerator randOpCodeWeight (gen, _options.opCodeProbability); |
|||
bool weightsDefined = _options.opCodeProbability.probabilities().size() == 255; |
|||
|
|||
for (auto i = 0; i < size; i++) |
|||
{ |
|||
uint8_t opcode = weightsDefined ? randOpCodeWeight() : randOpCodeGen(); |
|||
dev::eth::InstructionInfo info = dev::eth::instructionInfo((dev::eth::Instruction) opcode); |
|||
|
|||
if (info.name.find_first_of("INVALID_INSTRUCTION") > 0) |
|||
{ |
|||
//Byte code is yet not implemented
|
|||
if (_options.useUndefinedOpCodes == false) |
|||
{ |
|||
i--; |
|||
continue; |
|||
} |
|||
} |
|||
else |
|||
code += fillArguments((dev::eth::Instruction) opcode, _options); |
|||
std::string byte = toCompactHex(opcode); |
|||
code += (byte == "") ? "00" : byte; |
|||
} |
|||
return code; |
|||
} |
|||
|
|||
std::string RandomCode::randomUniIntHex() |
|||
{ |
|||
refreshSeed(); |
|||
return "0x" + toCompactHex((int)randUniIntGen()); |
|||
} |
|||
|
|||
int RandomCode::randomUniInt() |
|||
{ |
|||
refreshSeed(); |
|||
return (int)randUniIntGen(); |
|||
} |
|||
|
|||
void RandomCode::refreshSeed() |
|||
{ |
|||
auto now = std::chrono::steady_clock::now().time_since_epoch(); |
|||
auto timeSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(now).count(); |
|||
gen.seed(static_cast<unsigned int>(timeSinceEpoch)); |
|||
} |
|||
|
|||
std::string RandomCode::getPushCode(std::string const& _hex) |
|||
{ |
|||
int length = _hex.length() / 2; |
|||
int pushCode = 96 + length - 1; |
|||
return toCompactHex(pushCode) + _hex; |
|||
} |
|||
|
|||
std::string RandomCode::getPushCode(int _value) |
|||
{ |
|||
std::string hexString = toCompactHex(_value); |
|||
return getPushCode(hexString); |
|||
} |
|||
|
|||
std::string RandomCode::fillArguments(dev::eth::Instruction _opcode, RandomCodeOptions const& _options) |
|||
{ |
|||
dev::eth::InstructionInfo info = dev::eth::instructionInfo(_opcode); |
|||
|
|||
std::string code; |
|||
bool smart = false; |
|||
unsigned num = info.args; |
|||
int rand = randUniIntGen() % 100; |
|||
if (rand < _options.smartCodeProbability) |
|||
smart = true; |
|||
|
|||
if (smart) |
|||
{ |
|||
switch (_opcode) |
|||
{ |
|||
case dev::eth::Instruction::CALL: |
|||
//(CALL gaslimit address value memstart1 memlen1 memstart2 memlen2)
|
|||
code += getPushCode(randUniIntGen() % 32); //memlen2
|
|||
code += getPushCode(randUniIntGen() % 32); //memstart2
|
|||
code += getPushCode(randUniIntGen() % 32); //memlen1
|
|||
code += getPushCode(randUniIntGen() % 32); //memlen1
|
|||
code += getPushCode(randUniIntGen()); //value
|
|||
code += getPushCode(toString(_options.getRandomAddress()));//address
|
|||
code += getPushCode(randUniIntGen()); //gaslimit
|
|||
break; |
|||
default: |
|||
smart = false; |
|||
} |
|||
} |
|||
|
|||
if (smart == false) |
|||
for (unsigned i = 0; i < num; i++) |
|||
{ |
|||
//generate random parameters
|
|||
int length = randOpLengGen(); |
|||
code += getPushCode(rndByteSequence(length)); |
|||
} |
|||
return code; |
|||
} |
|||
|
|||
|
|||
//Ramdom Code Options
|
|||
RandomCodeOptions::RandomCodeOptions() : useUndefinedOpCodes(false), smartCodeProbability(50) |
|||
{ |
|||
//each op code with same weight-probability
|
|||
for (auto i = 0; i < 255; i++) |
|||
mapWeights.insert(std::pair<int, int>(i, 50)); |
|||
setWeights(); |
|||
} |
|||
|
|||
void RandomCodeOptions::setWeight(dev::eth::Instruction _opCode, int _weight) |
|||
{ |
|||
mapWeights.at((int)_opCode) = _weight; |
|||
setWeights(); |
|||
} |
|||
|
|||
void RandomCodeOptions::addAddress(dev::Address const& _address) |
|||
{ |
|||
addressList.push_back(_address); |
|||
} |
|||
|
|||
dev::Address RandomCodeOptions::getRandomAddress() const |
|||
{ |
|||
if (addressList.size() > 0) |
|||
{ |
|||
int index = RandomCode::randomUniInt() % addressList.size(); |
|||
return addressList[index]; |
|||
} |
|||
return Address(RandomCode::rndByteSequence(20)); |
|||
} |
|||
|
|||
void RandomCodeOptions::setWeights() |
|||
{ |
|||
std::vector<int> weights; |
|||
for (auto const& element: mapWeights) |
|||
weights.push_back(element.second); |
|||
opCodeProbability = boostDescreteDistrib(weights); |
|||
} |
|||
|
|||
|
|||
BOOST_AUTO_TEST_SUITE(RandomCodeTests) |
|||
|
|||
BOOST_AUTO_TEST_CASE(rndCode) |
|||
{ |
|||
std::string code; |
|||
std::cerr << "Testing Random Code: "; |
|||
try |
|||
{ |
|||
code = dev::test::RandomCode::generate(10); |
|||
} |
|||
catch(...) |
|||
{ |
|||
BOOST_ERROR("Exception thrown when generating random code!"); |
|||
} |
|||
std::cerr << code; |
|||
} |
|||
|
|||
BOOST_AUTO_TEST_SUITE_END() |
|||
|
|||
} |
|||
} |
@ -0,0 +1,97 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/** @file fuzzHelper.h
|
|||
* @author Dimitry Khokhlov <winsvega@mail.ru> |
|||
* @date 2015 |
|||
*/ |
|||
|
|||
#include <string> |
|||
#include <boost/random.hpp> |
|||
#include <boost/filesystem/path.hpp> |
|||
|
|||
#include <test/TestHelper.h> |
|||
#include <libdevcore/CommonIO.h> |
|||
#include <libdevcore/CommonData.h> |
|||
#include <libevmcore/Instruction.h> |
|||
|
|||
#pragma once |
|||
|
|||
namespace dev |
|||
{ |
|||
namespace test |
|||
{ |
|||
|
|||
typedef boost::random::uniform_int_distribution<> boostIntDistrib; |
|||
typedef boost::random::discrete_distribution<> boostDescreteDistrib; |
|||
|
|||
typedef boost::random::variate_generator<boost::mt19937&, boostIntDistrib > boostIntGenerator; |
|||
typedef boost::random::variate_generator<boost::mt19937&, boostDescreteDistrib > boostWeightGenerator; |
|||
|
|||
struct RandomCodeOptions |
|||
{ |
|||
public: |
|||
RandomCodeOptions(); |
|||
void setWeight(dev::eth::Instruction _opCode, int _weight); |
|||
void addAddress(dev::Address const& _address); |
|||
dev::Address getRandomAddress() const; |
|||
|
|||
bool useUndefinedOpCodes; |
|||
int smartCodeProbability; |
|||
boostDescreteDistrib opCodeProbability; |
|||
private: |
|||
void setWeights(); |
|||
std::map<int, int> mapWeights; |
|||
std::vector<dev::Address> addressList; |
|||
}; |
|||
|
|||
enum class SizeStrictness |
|||
{ |
|||
Strict, |
|||
Random |
|||
}; |
|||
|
|||
class RandomCode |
|||
{ |
|||
public: |
|||
/// Generate random vm code
|
|||
static std::string generate(int _maxOpNumber = 1, RandomCodeOptions _options = RandomCodeOptions()); |
|||
|
|||
/// Generate random byte string of a given length
|
|||
static std::string rndByteSequence(int _length = 1, SizeStrictness _sizeType = SizeStrictness::Strict); |
|||
|
|||
/// Generate random uniForm Int with reasonable value 0..0x7fffffff
|
|||
static std::string randomUniIntHex(); |
|||
static int randomUniInt(); |
|||
|
|||
private: |
|||
static std::string fillArguments(dev::eth::Instruction _opcode, RandomCodeOptions const& _options); |
|||
static std::string getPushCode(int _value); |
|||
static std::string getPushCode(std::string const& _hex); |
|||
static void refreshSeed(); |
|||
|
|||
static boost::random::mt19937 gen; ///< Random generator
|
|||
static boostIntDistrib opCodeDist; ///< 0..255 opcodes
|
|||
static boostIntDistrib opLengDist; ///< 1..32 byte string
|
|||
static boostIntDistrib uniIntDist; ///< 0..0x7fffffff
|
|||
|
|||
static boostIntGenerator randUniIntGen; ///< Generate random UniformInt from uniIntDist
|
|||
static boostIntGenerator randOpCodeGen; ///< Generate random value from opCodeDist
|
|||
static boostIntGenerator randOpLengGen; ///< Generate random length from opLengDist
|
|||
}; |
|||
|
|||
} |
|||
} |
@ -1,192 +0,0 @@ |
|||
/*
|
|||
This file is part of cpp-ethereum. |
|||
|
|||
cpp-ethereum is free software: you can redistribute it and/or modify |
|||
it under the terms of the GNU General Public License as published by |
|||
the Free Software Foundation, either version 3 of the License, or |
|||
(at your option) any later version. |
|||
|
|||
cpp-ethereum is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
GNU General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU General Public License |
|||
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
/**
|
|||
* @author Christian <c@ethdev.com> |
|||
* @date 2014 |
|||
* Unit tests for the solidity compiler. |
|||
*/ |
|||
|
|||
#include <string> |
|||
#include <iostream> |
|||
#include <boost/test/unit_test.hpp> |
|||
#include <libdevcore/Log.h> |
|||
#include <libsolidity/Scanner.h> |
|||
#include <libsolidity/Parser.h> |
|||
#include <libsolidity/NameAndTypeResolver.h> |
|||
#include <libsolidity/Compiler.h> |
|||
#include <libsolidity/AST.h> |
|||
|
|||
using namespace std; |
|||
using namespace dev::eth; |
|||
|
|||
namespace dev |
|||
{ |
|||
namespace solidity |
|||
{ |
|||
namespace test |
|||
{ |
|||
|
|||
namespace |
|||
{ |
|||
|
|||
bytes compileContract(const string& _sourceCode) |
|||
{ |
|||
Parser parser; |
|||
ASTPointer<SourceUnit> sourceUnit; |
|||
BOOST_REQUIRE_NO_THROW(sourceUnit = parser.parse(make_shared<Scanner>(CharStream(_sourceCode)))); |
|||
NameAndTypeResolver resolver({}); |
|||
resolver.registerDeclarations(*sourceUnit); |
|||
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes()) |
|||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get())) |
|||
{ |
|||
BOOST_REQUIRE_NO_THROW(resolver.resolveNamesAndTypes(*contract)); |
|||
} |
|||
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes()) |
|||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get())) |
|||
{ |
|||
BOOST_REQUIRE_NO_THROW(resolver.checkTypeRequirements(*contract)); |
|||
} |
|||
for (ASTPointer<ASTNode> const& node: sourceUnit->getNodes()) |
|||
if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get())) |
|||
{ |
|||
Compiler compiler; |
|||
compiler.compileContract(*contract, map<ContractDefinition const*, bytes const*>{}); |
|||
|
|||
// debug
|
|||
//compiler.streamAssembly(cout);
|
|||
return compiler.getAssembledBytecode(); |
|||
} |
|||
BOOST_FAIL("No contract found in source."); |
|||
return bytes(); |
|||
} |
|||
|
|||
/// Checks that @a _compiledCode is present starting from offset @a _offset in @a _expectation.
|
|||
/// This is necessary since the compiler will add boilerplate add the beginning that is not
|
|||
/// tested here.
|
|||
void checkCodePresentAt(bytes const& _compiledCode, bytes const& _expectation, unsigned _offset) |
|||
{ |
|||
BOOST_REQUIRE(_compiledCode.size() >= _offset + _expectation.size()); |
|||
auto checkStart = _compiledCode.begin() + _offset; |
|||
BOOST_CHECK_EQUAL_COLLECTIONS(checkStart, checkStart + _expectation.size(), |
|||
_expectation.begin(), _expectation.end()); |
|||
} |
|||
|
|||
} // end anonymous namespace
|
|||
|
|||
BOOST_AUTO_TEST_SUITE(SolidityCompiler) |
|||
|
|||
BOOST_AUTO_TEST_CASE(smoke_test) |
|||
{ |
|||
char const* sourceCode = "contract test {\n" |
|||
" function f() { var x = 2; }\n" |
|||
"}\n"; |
|||
bytes code = compileContract(sourceCode); |
|||
|
|||
unsigned boilerplateSize = 73; |
|||
bytes expectation({byte(Instruction::JUMPDEST), |
|||
byte(Instruction::PUSH1), 0x0, // initialize local variable x
|
|||
byte(Instruction::PUSH1), 0x2, |
|||
byte(Instruction::SWAP1), |
|||
byte(Instruction::POP), |
|||
byte(Instruction::JUMPDEST), |
|||
byte(Instruction::POP), |
|||
byte(Instruction::JUMP)}); |
|||
checkCodePresentAt(code, expectation, boilerplateSize); |
|||
} |
|||
|
|||
BOOST_AUTO_TEST_CASE(ifStatement) |
|||
{ |
|||
char const* sourceCode = "contract test {\n" |
|||
" function f() { bool x; if (x) 77; else if (!x) 78; else 79; }" |
|||
"}\n"; |
|||
bytes code = compileContract(sourceCode); |
|||
unsigned shift = 60; |
|||
unsigned boilerplateSize = 73; |
|||
bytes expectation({ |
|||
byte(Instruction::JUMPDEST), |
|||
byte(Instruction::PUSH1), 0x0, |
|||
byte(Instruction::DUP1), |
|||
byte(Instruction::ISZERO), |
|||
byte(Instruction::PUSH1), byte(0x0f + shift), // "false" target
|
|||
byte(Instruction::JUMPI), |
|||
// "if" body
|
|||
byte(Instruction::PUSH1), 0x4d, |
|||
byte(Instruction::POP), |
|||
byte(Instruction::PUSH1), byte(0x21 + shift), |
|||
byte(Instruction::JUMP), |
|||
// new check "else if" condition
|
|||
byte(Instruction::JUMPDEST), |
|||
byte(Instruction::DUP1), |
|||
byte(Instruction::ISZERO), |
|||
byte(Instruction::ISZERO), |
|||
byte(Instruction::PUSH1), byte(0x1c + shift), |
|||
byte(Instruction::JUMPI), |
|||
// "else if" body
|
|||
byte(Instruction::PUSH1), 0x4e, |
|||
byte(Instruction::POP), |
|||
byte(Instruction::PUSH1), byte(0x20 + shift), |
|||
byte(Instruction::JUMP), |
|||
// "else" body
|
|||
byte(Instruction::JUMPDEST), |
|||
byte(Instruction::PUSH1), 0x4f, |
|||
byte(Instruction::POP), |
|||
}); |
|||
checkCodePresentAt(code, expectation, boilerplateSize); |
|||
} |
|||
|
|||
BOOST_AUTO_TEST_CASE(loops) |
|||
{ |
|||
char const* sourceCode = "contract test {\n" |
|||
" function f() { while(true){1;break;2;continue;3;return;4;} }" |
|||
"}\n"; |
|||
bytes code = compileContract(sourceCode); |
|||
unsigned shift = 60; |
|||
unsigned boilerplateSize = 73; |
|||
bytes expectation({byte(Instruction::JUMPDEST), |
|||
byte(Instruction::JUMPDEST), |
|||
byte(Instruction::PUSH1), 0x1, |
|||
byte(Instruction::ISZERO), |
|||
byte(Instruction::PUSH1), byte(0x21 + shift), |
|||
byte(Instruction::JUMPI), |
|||
byte(Instruction::PUSH1), 0x1, |
|||
byte(Instruction::POP), |
|||
byte(Instruction::PUSH1), byte(0x21 + shift), |
|||
byte(Instruction::JUMP), // break
|
|||
byte(Instruction::PUSH1), 0x2, |
|||
byte(Instruction::POP), |
|||
byte(Instruction::PUSH1), byte(0x2 + shift), |
|||
byte(Instruction::JUMP), // continue
|
|||
byte(Instruction::PUSH1), 0x3, |
|||
byte(Instruction::POP), |
|||
byte(Instruction::PUSH1), byte(0x22 + shift), |
|||
byte(Instruction::JUMP), // return
|
|||
byte(Instruction::PUSH1), 0x4, |
|||
byte(Instruction::POP), |
|||
byte(Instruction::PUSH1), byte(0x2 + shift), |
|||
byte(Instruction::JUMP), |
|||
byte(Instruction::JUMPDEST), |
|||
byte(Instruction::JUMPDEST), |
|||
byte(Instruction::JUMP)}); |
|||
|
|||
checkCodePresentAt(code, expectation, boilerplateSize); |
|||
} |
|||
|
|||
BOOST_AUTO_TEST_SUITE_END() |
|||
|
|||
} |
|||
} |
|||
} // end namespaces
|
Loading…
Reference in new issue