Skip to content
This repository has been archived by the owner on Jan 15, 2025. It is now read-only.

Commit

Permalink
Add bi_t::within() to test if big integer fits in an integral type
Browse files Browse the repository at this point in the history
  • Loading branch information
OTheDev committed Feb 23, 2024
1 parent 37e57dc commit 6ef6dac
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 1 deletion.
2 changes: 2 additions & 0 deletions include/bi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ class BI_API bi_t {
int sign() const noexcept;
bool odd() const noexcept;
bool even() const noexcept;
template <std::integral T>
bool within() const noexcept;

// Friends
BI_API friend std::ostream& operator<<(std::ostream& os, const bi_t& x);
Expand Down
28 changes: 27 additions & 1 deletion src/bi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,28 @@ std::string bi_t::to_string() const {
* @complexity O(1)
*/

/**
* @brief Return `true` if this integer fits in an integral type T, `false`
* otherwise.
*
* For `bi_t` object `x` and integral type `T`, `x.within<T>()` evaluates to
* @code
* x >= std::numeric_limits<T>::min() && x <= std::numeric_limits<T>::max()
* @endcode
*
* Example:
* @code{.cpp}
* bi_t x = std::numeric_limits<int32_t>::max();
* bool fits_in_int32 = x.within<int32_t>(); // true
* bool fits_in_int16 = x.within<int16_t>(); // false
* @endcode
*/
template <std::integral T>
bool bi_t::within() const noexcept {
return (*this) >= std::numeric_limits<T>::min() &&
(*this) <= std::numeric_limits<T>::max();
}

///@}

/**
Expand Down Expand Up @@ -866,12 +888,16 @@ bi_t abs(const bi_t& value) {
return value;
}

/// @cond
BI_INST_TEMPLATE_FOR_INTEGRAL_TYPES(bi_t::bi_t, BI_EMPTY);
BI_INST_TEMPLATE_FOR_INTEGRAL_TYPES(bi_t& bi_t::operator=, BI_EMPTY);

BI_INST_TEMPLATE_FOR_INTEGRAL_TYPES(std::strong_ordering bi_t::operator<=>,
const noexcept);
BI_INST_TEMPLATE_FOR_INTEGRAL_TYPES(bool bi_t::operator==, const noexcept);

BI_INST_TEMPLATE_FOR_INTEGRAL_TYPES_CONV(bi_t::operator, const noexcept);

BI_INST_TEMPLATE_FOR_INTEGRAL_TYPES_NOARG(bool bi_t::within, const noexcept);
/// @endcond

}; // namespace bi
18 changes: 18 additions & 0 deletions src/inst_integral.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,15 @@ Extension Signed/Unsigned Integer Types (GCC, Clang)
#define BI_INST_TEMPLATE_FOR_EXTENSION_INTEGRAL_TYPES_CONV(FUNC, END) \
template FUNC __int128() END; \
template FUNC unsigned __int128() END;

#define BI_INST_TEMPLATE_FOR_EXTENSION_INTEGRAL_TYPES_NOARG(FUNC, END) \
template FUNC<__int128>() END; \
template FUNC<unsigned __int128>() END;
#else
#define BI_INST_TEMPLATE_FOR_EXTENSION_INTEGRAL_TYPES(FUNC, END)
#define BI_INST_TEMPLATE_FOR_EXTENSION_INTEGRAL_TYPES_ARG(FUNC, ARG)
#define BI_INST_TEMPLATE_FOR_EXTENSION_INTEGRAL_TYPES_CONV(FUNC, END)
#define BI_INST_TEMPLATE_FOR_EXTENSION_INTEGRAL_TYPES_NOARG(FUNC, END)
#endif

#define BI_INST_TEMPLATE_FOR_INTEGRAL_TYPES(FUNC, END) \
Expand Down Expand Up @@ -88,6 +93,19 @@ Extension Signed/Unsigned Integer Types (GCC, Clang)
template FUNC unsigned long long() END; \
BI_INST_TEMPLATE_FOR_EXTENSION_INTEGRAL_TYPES_CONV(FUNC, END)

#define BI_INST_TEMPLATE_FOR_INTEGRAL_TYPES_NOARG(FUNC, END) \
template FUNC<signed char>() END; \
template FUNC<short>() END; \
template FUNC<int>() END; \
template FUNC<long>() END; \
template FUNC<long long>() END; \
template FUNC<unsigned char>() END; \
template FUNC<unsigned short>() END; \
template FUNC<unsigned>() END; \
template FUNC<unsigned long>() END; \
template FUNC<unsigned long long>() END; \
BI_INST_TEMPLATE_FOR_EXTENSION_INTEGRAL_TYPES_NOARG(FUNC, END)

// NOLINTEND(cppcoreguidelines-macro-usage)

#endif // BI_SRC_INST_INTEGRAL_HPP_
30 changes: 30 additions & 0 deletions test/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1700,6 +1700,36 @@ TEST_F(BitwiseOperatorsTest, UnaryComplement) {
}
}

TEST_F(BITest, WithinIntegral) {
bi_t x;

EXPECT_TRUE(x.within<digit>());

x = digit_max;
EXPECT_TRUE(x.within<digit>());
EXPECT_FALSE(x.within<sdigit>());

x += 1;
EXPECT_FALSE(x.within<digit>());

x = -static_cast<sddigit>(digit_max);
EXPECT_FALSE(x.within<digit>());
EXPECT_TRUE(x.within<sddigit>());
x -= 1;
EXPECT_TRUE(x.within<sddigit>());

x = ddigit_max;
EXPECT_TRUE(x.within<ddigit>());
EXPECT_FALSE(x.within<digit>());

// From documentation
x = std::numeric_limits<int32_t>::max();
bool fits_in_int32 = x.within<int32_t>(); // true
bool fits_in_int16 = x.within<int16_t>(); // false
EXPECT_TRUE(fits_in_int32);
EXPECT_FALSE(fits_in_int16);
}

// NOLINTEND(cppcoreguidelines-avoid-magic-numbers)

} // namespace

0 comments on commit 6ef6dac

Please sign in to comment.