mcl-1.0.1: cbits/include/hs_mcl_misc.hpp
#ifndef HAVE_HS_MCL_MISC
#define HAVE_HS_MCL_MISC
#include <mcl/fp.hpp>
namespace hs_mcl {
// On x86_32 mp_limb_t is a typedef for unsigned long int, whereas mcl::fp::Unit
// is typedef for unsigned int. These, even though of the same size, are
// distinct types, hence compiler complains when we pass a pointer to the former
// when a pointer to the latter is expected. Below is used to safely bridge that
// gap.
union limb_unit_compat
{
limb_unit_compat(const mp_limb_t *limbs_)
: limbs(limbs_)
{ }
const mp_limb_t *limbs;
const mcl::fp::Unit *units;
static_assert(sizeof(*limbs) == sizeof(*units),
"mp_limb_t and mcl::fp::Unit have different size");
};
// In order to avoid using foreign pointers to manage memory for MCL numeric
// classes inside Haskell we take advantage of the fact that all of them are
// trivially destructible. As there is no need to run the destructor, we can
// allocate memory for them inside Haskell and construct them at C++ level
// within that memory block using placement new operator.
//
// This class statically guarantees that objects we construct and copy are
// trivially destructible classes. If at any point in time some of them cease to
// be so (which is highly doubtful, but nevertheless), it can be easily adjusted
// to use ordinary operator new (unfortunately then we can't escape ForeignPtr
// management in Haskell).
struct mem_util
{
template <typename TargetT>
inline static void init(TargetT *target)
{
static_assert(std::is_class<TargetT>::value,
"Target is not a class");
mem_util_impl<TargetT, TargetT,
std::is_trivially_destructible<TargetT>::value
>::init(target);
}
template <typename TargetT, typename SourceT>
inline static void copy(TargetT *target, SourceT &&source)
{
static_assert(std::is_class<TargetT>::value,
"Target is not a class");
mem_util_impl<TargetT, SourceT,
std::is_trivially_destructible<TargetT>::value
>::copy(target,
std::forward<SourceT>(source));
}
private:
template <typename TargetT, typename SourceT,
bool is_trivially_destructible>
struct mem_util_impl
{
static_assert(is_trivially_destructible,
"Target is not trivially destructible");
};
template <typename TargetT, typename SourceT>
struct mem_util_impl<TargetT, SourceT, true>
{
inline static void init(TargetT *target)
{
new (target) TargetT{};
}
inline static void copy(TargetT *target, SourceT &&source)
{
new (target) TargetT{std::forward<SourceT>(source)};
}
};
};
////////////////////////////////////////////////////////////
inline void mpz_class_to_gmp_integer(const mpz_class &z, mp_limb_t *result,
const size_t result_length_bytes)
{
mpz_srcptr mp = z.get_mpz_t();
size_t n = mpz_size(mp);
assert(n * sizeof(mp->_mp_d[0]) == result_length_bytes);
std::copy(mp->_mp_d, mp->_mp_d + n, result);
}
}
#endif // HAVE_HS_MCL_MISC