Skip to content

Commit

Permalink
multiprecision: big_uint: refactor operators WIP 7
Browse files Browse the repository at this point in the history
  • Loading branch information
ioxid committed Dec 13, 2024
1 parent d27e313 commit 8d703b3
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@
#include "nil/crypto3/multiprecision/detail/big_uint/arithmetic.hpp"
#include "nil/crypto3/multiprecision/detail/big_uint/parsing.hpp"
#include "nil/crypto3/multiprecision/detail/big_uint/storage.hpp"
#include "nil/crypto3/multiprecision/detail/big_uint/type_traits.hpp"
#include "nil/crypto3/multiprecision/detail/big_uint/type_traits.hpp" // IWYU pragma: export
#include "nil/crypto3/multiprecision/detail/config.hpp"
#include "nil/crypto3/multiprecision/detail/endian.hpp"
#include "nil/crypto3/multiprecision/detail/type_traits.hpp"

namespace nil::crypto3::multiprecision {
/**
Expand Down Expand Up @@ -937,33 +938,41 @@ namespace nil::crypto3::multiprecision {

NIL_CO3_MP_BIG_UINT_INTEGRAL_TEMPLATE
constexpr auto operator/(const T1& a, const T2& b) noexcept {
using big_uint_a = std::decay_t<decltype(detail::as_big_uint(a))>;
decltype(auto) a_unsigned = detail::unsigned_or_throw(a);
decltype(auto) b_unsigned = detail::unsigned_or_throw(b);
using big_uint_a = std::decay_t<decltype(detail::as_big_uint(a_unsigned))>;
big_uint_a result;
big_uint_a modulus;
detail::divide(&result, detail::as_big_uint(a), detail::as_big_uint(b), modulus);
detail::divide(&result, detail::as_big_uint(a_unsigned), detail::as_big_uint(b_unsigned),
modulus);
return static_cast<detail::largest_big_uint_t<T1, T2>>(result);
}
NIL_CO3_MP_BIG_UINT_INTEGRAL_ASSIGNMENT_TEMPLATE
constexpr auto& operator/=(big_uint_t& a, const T& b) noexcept {
decltype(auto) b_unsigned = detail::unsigned_or_throw(b);
big_uint_t result;
big_uint_t modulus;
detail::divide(&result, a, detail::as_big_uint(b), modulus);
detail::divide(&result, a, detail::as_big_uint(b_unsigned), modulus);
a = result;
return a;
}

NIL_CO3_MP_BIG_UINT_INTEGRAL_TEMPLATE
constexpr auto operator%(const T1& a, const T2& b) {
using big_uint_a = std::decay_t<decltype(detail::as_big_uint(a))>;
decltype(auto) a_unsigned = detail::unsigned_or_throw(a);
decltype(auto) b_unsigned = detail::unsigned_or_throw(b);
using big_uint_a = std::decay_t<decltype(detail::as_big_uint(a_unsigned))>;
big_uint_a modulus;
detail::divide(static_cast<big_uint_a*>(nullptr), detail::as_big_uint(a),
detail::as_big_uint(b), modulus);
detail::divide(static_cast<big_uint_a*>(nullptr), detail::as_big_uint(a_unsigned),
detail::as_big_uint(b_unsigned), modulus);
return static_cast<detail::largest_big_uint_t<T1, T2>>(modulus);
}
NIL_CO3_MP_BIG_UINT_INTEGRAL_ASSIGNMENT_TEMPLATE
constexpr auto& operator%=(big_uint_t& a, const T& b) {
decltype(auto) b_unsigned = detail::unsigned_or_throw(b);
big_uint_t modulus;
detail::divide(static_cast<big_uint_t*>(nullptr), a, detail::as_big_uint(b), modulus);
detail::divide(static_cast<big_uint_t*>(nullptr), a, detail::as_big_uint(b_unsigned),
modulus);
a = modulus;
return a;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
#include <algorithm>
#include <climits>
#include <cstddef>
#include <stdexcept>
#include <type_traits>

#include "nil/crypto3/multiprecision/detail/big_uint/storage.hpp"
#include "nil/crypto3/multiprecision/detail/type_traits.hpp"

namespace nil::crypto3::multiprecision {
template<std::size_t Bits>
Expand Down Expand Up @@ -38,44 +38,35 @@ namespace nil::crypto3::multiprecision {
big_uint<std::max(get_bits<T1>(), get_bits<T2>())>,
std::conditional_t<is_big_uint_v<T1>, T1, T2>>;

template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
template<typename T,
std::enable_if_t<std::is_integral_v<T> && std::is_unsigned_v<T>, int> = 0>
constexpr big_uint<sizeof(T) * CHAR_BIT> as_big_uint(const T& a) {
if constexpr (std::is_signed_v<T>) {
if (a < 0) {
throw std::invalid_argument("as_big_uint: negative value");
}
}
return static_cast<big_uint<sizeof(T) * CHAR_BIT>>(a);
}

template<std::size_t Bits>
constexpr const auto& as_big_uint(const big_uint<Bits>& a) {
return a;
template<typename T, std::enable_if_t<is_big_uint_v<std::decay_t<T>>, int> = 0>
constexpr decltype(auto) as_big_uint(T&& a) {
return std::forward<T>(a);
}

template<
typename T,
std::enable_if_t<std::is_integral_v<T> && sizeof(T) * CHAR_BIT <= limb_bits, int> = 0>
constexpr limb_type as_limb_type_or_big_uint(const T& a) {
if constexpr (std::is_signed_v<T>) {
if (a < 0) {
throw std::invalid_argument("as_limb_type_or_big_uint: negative value");
}
}
return static_cast<limb_type>(a);
return static_cast<limb_type>(unsigned_or_throw(a));
}

template<typename T,
std::enable_if_t<!(std::is_integral_v<T> && sizeof(T) * CHAR_BIT <= limb_bits) &&
!is_big_uint_v<T>,
int> = 0>
constexpr auto as_limb_type_or_big_uint(const T& a) {
return as_big_uint(a);
return as_big_uint(unsigned_or_throw(a));
}

template<std::size_t Bits>
constexpr const auto& as_limb_type_or_big_uint(const big_uint<Bits>& a) {
return a;
template<typename T, std::enable_if_t<is_big_uint_v<std::decay_t<T>>, int> = 0>
constexpr decltype(auto) as_limb_type_or_big_uint(T&& a) {
return std::forward<T>(a);
}
} // namespace detail
} // namespace nil::crypto3::multiprecision
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,25 @@
#include <type_traits>

#include "nil/crypto3/multiprecision/detail/big_uint/big_uint_impl.hpp"
#include "nil/crypto3/multiprecision/detail/type_traits.hpp"

namespace nil::crypto3::multiprecision {
template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
constexpr std::size_t msb(T a) {
// TODO(ioxid): optimize
return detail::as_big_uint(a).msb();
return detail::as_big_uint(detail::unsigned_or_throw(a)).msb();
}

template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
constexpr std::size_t lsb(T a) {
// TODO(ioxid): optimize
return detail::as_big_uint(a).lsb();
return detail::as_big_uint(detail::unsigned_or_throw(a)).lsb();
}

template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
constexpr bool bit_test(T a, std::size_t index) {
// TODO(ioxid): optimize
return detail::as_big_uint(a).bit_test(index);
return detail::as_big_uint(detail::unsigned_or_throw(a)).bit_test(index);
}

template<typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include <limits>
#include <type_traits>

#include "nil/crypto3/multiprecision/detail/big_uint/big_uint_impl.hpp"
#include "nil/crypto3/multiprecision/detail/big_uint/ops/powm.hpp"

namespace nil::crypto3::multiprecision {
Expand All @@ -14,7 +13,8 @@ namespace nil::crypto3::multiprecision {
int> = 0>
constexpr T3 powm(T1 &&b, T2 &&e, T3 m) {
// TODO(ioxid): optimize
return static_cast<T3>(nil::crypto3::multiprecision::powm(
std::forward<T1>(b), std::forward<T2>(e), detail::as_big_uint(m)));
return static_cast<T3>(
nil::crypto3::multiprecision::powm(std::forward<T1>(b), std::forward<T2>(e),
detail::as_big_uint(detail::unsigned_or_throw(m))));
}
} // namespace nil::crypto3::multiprecision
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <limits>
#include <stdexcept>
#include <type_traits>

namespace nil::crypto3::multiprecision::detail {
Expand All @@ -10,4 +11,17 @@ namespace nil::crypto3::multiprecision::detail {

template<typename T>
constexpr bool is_unsigned_integer_v = is_integer_v<T> && !std::numeric_limits<T>::is_signed;

template<typename T, std::enable_if_t<is_unsigned_integer_v<std::decay_t<T>>, int> = 0>
constexpr decltype(auto) unsigned_or_throw(T&& a) {
return std::forward<T>(a);
}

template<typename T, std::enable_if_t<std::is_signed_v<T>, int> = 0>
constexpr std::make_unsigned_t<T> unsigned_or_throw(const T& a) {
if (a < 0) {
throw std::invalid_argument("nonnegative value expected");
}
return static_cast<std::make_unsigned_t<T>>(a);
}
} // namespace nil::crypto3::multiprecision::detail

0 comments on commit 8d703b3

Please sign in to comment.