Skip to content

Commit

Permalink
Add hashes for booleans, integers and floating point
Browse files Browse the repository at this point in the history
Closes foonathan#53, fixes foonathan#52.
  • Loading branch information
foonathan committed Nov 14, 2017
1 parent c552b16 commit 0320c2e
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 48 deletions.
19 changes: 17 additions & 2 deletions include/type_safe/boolean.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <iosfwd>
#include <type_traits>
#include <functional>
#include <utility>

#include <type_safe/detail/force_inline.hpp>
Expand Down Expand Up @@ -152,7 +153,7 @@ namespace type_safe
/// \module types
template <typename Char, class CharTraits>
std::basic_istream<Char, CharTraits>& operator>>(std::basic_istream<Char, CharTraits>& in,
boolean& b)
boolean& b)
{
bool val;
in >> val;
Expand All @@ -165,7 +166,7 @@ namespace type_safe
/// \module types
template <typename Char, class CharTraits>
std::basic_ostream<Char, CharTraits>& operator<<(std::basic_ostream<Char, CharTraits>& out,
const boolean& b)
const boolean& b)
{
return out << static_cast<bool>(b);
}
Expand Down Expand Up @@ -210,4 +211,18 @@ namespace type_safe
#undef TYPE_SAFE_DETAIL_MAKE_PREDICATE
} // namespace type_safe

namespace std
{
/// Hash specialization for [ts::boolean]().
/// \module types
template <>
struct hash<type_safe::boolean>
{
std::size_t operator()(type_safe::boolean b) const noexcept
{
return std::hash<bool>()(static_cast<bool>(b));
}
};
} // namespace std

#endif // TYPE_SAFE_BOOLEAN_HPP_INCLUDED
58 changes: 35 additions & 23 deletions include/type_safe/floating_point.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#define TYPE_SAFE_FLOATING_POINT_HPP_INCLUDED

#include <iosfwd>
#include <functional>
#include <type_traits>

#include <type_safe/detail/force_inline.hpp>
Expand All @@ -20,9 +21,9 @@ namespace type_safe
{
template <typename From, typename To>
struct is_safe_floating_point_conversion
: std::integral_constant<bool, std::is_floating_point<From>::value
&& std::is_floating_point<To>::value
&& sizeof(From) <= sizeof(To)>
: std::integral_constant<bool, std::is_floating_point<From>::value
&& std::is_floating_point<To>::value
&& sizeof(From) <= sizeof(To)>
{
};

Expand All @@ -36,8 +37,8 @@ namespace type_safe

template <typename A, typename B>
struct is_safe_floating_point_comparision
: std::integral_constant<bool, is_safe_floating_point_conversion<A, B>::value
|| is_safe_floating_point_conversion<B, A>::value>
: std::integral_constant<bool, is_safe_floating_point_conversion<A, B>::value
|| is_safe_floating_point_conversion<B, A>::value>
{
};

Expand All @@ -51,16 +52,15 @@ namespace type_safe

template <typename A, typename B>
struct is_safe_floating_point_operation
: std::integral_constant<bool, std::is_floating_point<A>::value
&& std::is_floating_point<B>::value>
: std::integral_constant<bool, std::is_floating_point<A>::value
&& std::is_floating_point<B>::value>
{
};

template <typename A, typename B>
using floating_point_result_t =
floating_point<typename std::enable_if<is_safe_floating_point_operation<A, B>::value,
typename std::conditional<sizeof(A) < sizeof(B),
B, A>::type>::type>;
using floating_point_result_t = floating_point<typename std::enable_if<
is_safe_floating_point_operation<A, B>::value,
typename std::conditional<sizeof(A) < sizeof(B), B, A>::type>::type>;
template <typename A, typename B>
using fallback_floating_point_result =
typename std::enable_if<!is_safe_floating_point_operation<A, B>::value>::type;
Expand Down Expand Up @@ -109,9 +109,8 @@ namespace type_safe
}

/// \exclude
template <
typename T,
typename = detail::fallback_safe_floating_point_conversion<T, floating_point_type>>
template <typename T, typename = detail::fallback_safe_floating_point_conversion<
T, floating_point_type>>
constexpr floating_point(T) = delete;

//=== assignment ===//
Expand Down Expand Up @@ -141,9 +140,8 @@ namespace type_safe
}

/// \exclude
template <
typename T,
typename = detail::fallback_safe_floating_point_conversion<T, floating_point_type>>
template <typename T, typename = detail::fallback_safe_floating_point_conversion<
T, floating_point_type>>
floating_point& operator=(T) = delete;

//=== conversion back ===//
Expand Down Expand Up @@ -181,7 +179,7 @@ namespace type_safe
* \module types
* \param 1
* \exclude
*/ \
*/ \
template <typename T, \
typename = detail::enable_safe_floating_point_conversion<T, floating_point_type>> \
TYPE_SAFE_FORCE_INLINE floating_point& operator Op(const T& other) noexcept \
Expand Down Expand Up @@ -260,7 +258,7 @@ namespace type_safe
#define TYPE_SAFE_DETAIL_MAKE_OP(Op) \
/** \group float_comp
* \param 2
* \exclude */ \
* \exclude */ \
template <typename A, typename B, \
typename = detail::enable_safe_floating_point_conversion<A, B>> \
TYPE_SAFE_FORCE_INLINE constexpr bool operator Op(const A& a, const floating_point<B>& b) \
Expand All @@ -269,7 +267,7 @@ namespace type_safe
} \
/** \group float_comp
* \param 2
* \exclude */ \
* \exclude */ \
template <typename A, typename B, \
typename = detail::enable_safe_floating_point_comparision<A, B>> \
TYPE_SAFE_FORCE_INLINE constexpr bool operator Op(const floating_point<A>& a, const B& b) \
Expand Down Expand Up @@ -358,7 +356,7 @@ namespace type_safe
/** \group float_binary_op */ \
template <typename A, typename B> \
TYPE_SAFE_FORCE_INLINE constexpr auto operator Op(const floating_point<A>& a, \
const B& b) noexcept \
const B& b) noexcept \
->detail::floating_point_result_t<A, B> \
{ \
return a Op floating_point<B>(b); \
Expand Down Expand Up @@ -426,7 +424,7 @@ namespace type_safe
/// \output_section Input/output
template <typename Char, class CharTraits, typename FloatT>
std::basic_istream<Char, CharTraits>& operator>>(std::basic_istream<Char, CharTraits>& in,
floating_point<FloatT>& f)
floating_point<FloatT>& f)
{
FloatT val;
in >> val;
Expand All @@ -438,10 +436,24 @@ namespace type_safe
/// \module types
template <typename Char, class CharTraits, typename FloatT>
std::basic_ostream<Char, CharTraits>& operator<<(std::basic_ostream<Char, CharTraits>& out,
const floating_point<FloatT>& f)
const floating_point<FloatT>& f)
{
return out << static_cast<FloatT>(f);
}
} // namespace type_safe

namespace std
{
/// Hash specialization for [ts::floating_point].
/// \module types
template <typename FloatT>
struct hash<type_safe::floating_point<FloatT>>
{
std::size_t operator()(const type_safe::floating_point<FloatT>& f) const noexcept
{
return std::hash<FloatT>()(static_cast<FloatT>(f));
}
};
} // namespace std

#endif // TYPE_SAFE_FLOATING_POINT_HPP_INCLUDED
57 changes: 34 additions & 23 deletions include/type_safe/integer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <iosfwd>
#include <limits>
#include <functional>
#include <type_traits>

#include <type_safe/detail/assert.hpp>
Expand All @@ -23,19 +24,17 @@ namespace type_safe
{
template <typename T>
struct is_integer
: std::integral_constant<bool,
std::is_integral<T>::value && !std::is_same<T, bool>::value
&& !std::is_same<T, char>::value>
: std::integral_constant<bool, std::is_integral<T>::value && !std::is_same<T, bool>::value
&& !std::is_same<T, char>::value>
{
};

template <typename From, typename To>
struct is_safe_integer_conversion
: std::
integral_constant<bool,
detail::is_integer<From>::value && detail::is_integer<To>::value
&& sizeof(From) <= sizeof(To)
&& std::is_signed<From>::value == std::is_signed<To>::value>
: std::integral_constant<bool,
detail::is_integer<From>::value && detail::is_integer<To>::value
&& sizeof(From) <= sizeof(To)
&& std::is_signed<From>::value == std::is_signed<To>::value>
{
};

Expand All @@ -49,9 +48,8 @@ namespace type_safe

template <typename A, typename B>
struct is_safe_integer_comparision
: std::integral_constant<bool,
is_safe_integer_conversion<A, B>::value
|| is_safe_integer_conversion<B, A>::value>
: std::integral_constant<bool, is_safe_integer_conversion<A, B>::value
|| is_safe_integer_conversion<B, A>::value>
{
};

Expand All @@ -65,16 +63,15 @@ namespace type_safe

template <typename A, typename B>
struct is_safe_integer_operation
: std::integral_constant<bool,
detail::is_integer<A>::value && detail::is_integer<B>::value
&& std::is_signed<A>::value == std::is_signed<B>::value>
: std::integral_constant<bool, detail::is_integer<A>::value && detail::is_integer<B>::value
&& std::is_signed<A>::value == std::is_signed<B>::value>
{
};

template <typename A, typename B>
struct integer_result_type
: std::enable_if<is_safe_integer_operation<A, B>::value,
typename std::conditional<sizeof(A) < sizeof(B), B, A>::type>
: std::enable_if<is_safe_integer_operation<A, B>::value,
typename std::conditional<sizeof(A) < sizeof(B), B, A>::type>
{
};

Expand Down Expand Up @@ -230,7 +227,7 @@ namespace type_safe
#define TYPE_SAFE_DETAIL_MAKE_OP(Op) \
/** \group compound_assign
* \param 1
* \exclude */ \
* \exclude */ \
template <typename T, typename = detail::enable_safe_integer_conversion<T, integer_type>> \
TYPE_SAFE_FORCE_INLINE integer& operator Op(const T& other) \
{ \
Expand Down Expand Up @@ -455,7 +452,7 @@ namespace type_safe
#define TYPE_SAFE_DETAIL_MAKE_OP(Op) \
/** \group int_comp
* \param 3
* \exclude */ \
* \exclude */ \
template <typename A, typename B, class Policy, \
typename = detail::enable_safe_integer_comparision<A, B>> \
TYPE_SAFE_FORCE_INLINE constexpr bool operator Op(const A& a, const integer<B, Policy>& b) \
Expand All @@ -464,7 +461,7 @@ namespace type_safe
} \
/** \group int_comp
* \param 3
* \exclude */ \
* \exclude */ \
template <typename A, class Policy, typename B, \
typename = detail::enable_safe_integer_comparision<A, B>> \
TYPE_SAFE_FORCE_INLINE constexpr bool operator Op(const integer<A, Policy>& a, const B& b) \
Expand Down Expand Up @@ -567,15 +564,15 @@ namespace type_safe
/// \exclude
#define TYPE_SAFE_DETAIL_MAKE_OP(Op) \
/** \exclude return
* \group int_binary_op */ \
* \group int_binary_op */ \
template <typename A, typename B, class Policy> \
TYPE_SAFE_FORCE_INLINE constexpr auto operator Op(const A& a, const integer<B, Policy>& b) \
->integer<detail::integer_result_t<A, B>, Policy> \
{ \
return integer<A, Policy>(a) Op b; \
} \
/** \exclude return
* \group int_binary_op */ \
* \group int_binary_op */ \
template <typename A, class Policy, typename B> \
TYPE_SAFE_FORCE_INLINE constexpr auto operator Op(const integer<A, Policy>& a, const B& b) \
->integer<detail::integer_result_t<A, B>, Policy> \
Expand Down Expand Up @@ -668,7 +665,7 @@ namespace type_safe
/// \output_section Input/output
template <typename Char, class CharTraits, typename IntegerT, class Policy>
std::basic_istream<Char, CharTraits>& operator>>(std::basic_istream<Char, CharTraits>& in,
integer<IntegerT, Policy>& i)
integer<IntegerT, Policy>& i)
{
IntegerT val;
in >> val;
Expand All @@ -680,10 +677,24 @@ namespace type_safe
/// \module types
template <typename Char, class CharTraits, typename IntegerT, class Policy>
std::basic_ostream<Char, CharTraits>& operator<<(std::basic_ostream<Char, CharTraits>& out,
const integer<IntegerT, Policy>& i)
const integer<IntegerT, Policy>& i)
{
return out << static_cast<IntegerT>(i);
}
} // namespace type_safe

namespace std
{
/// Hash specialization for [ts::integer].
/// \module types
template <typename IntegerT, class Policy>
struct hash<type_safe::integer<IntegerT, Policy>>
{
std::size_t operator()(const type_safe::integer<IntegerT, Policy>& i) const noexcept
{
return std::hash<IntegerT>()(static_cast<IntegerT>(i));
}
};
} // namespace std

#endif // TYPE_SAFE_INTEGER_HPP_INCLUDED

0 comments on commit 0320c2e

Please sign in to comment.