Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1273,3 +1273,70 @@ jobs:
ctest --output-on-failure --no-tests=error
cd $GITHUB_WORKSPACE
done

cmake-module-test:
strategy:
fail-fast: false

runs-on: ubuntu-24.04

env:
# clang/libc++ version used to build the module. Needs a libc++ new enough to
# mix `import std` with textual libc++ includes (18 and 19 have std-module bugs).
LLVM_VERSION: "20"
# Pinned so the experimental `import std` feature UUID below stays valid.
CMAKE_VERSION: 4.4.0
# CMake gates `import std` behind this UUID; it is specific to the CMake version.
IMPORT_STD_UUID: f35a9ac6-8463-4d38-8eec-5d6008153e7d

steps:
- uses: actions/checkout@v4

- name: Install toolchain
run: |
# A recent clang + libc++ (for `import std`), clang-scan-deps (module
# dependency scanning), Ninja (required for C++ modules) and a pinned CMake.
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh $LLVM_VERSION
sudo apt-get install -y clang-tools-$LLVM_VERSION libc++-$LLVM_VERSION-dev libc++abi-$LLVM_VERSION-dev ninja-build
wget -q https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-linux-x86_64.tar.gz
sudo tar -xzf cmake-$CMAKE_VERSION-linux-x86_64.tar.gz -C /opt
echo "/opt/cmake-$CMAKE_VERSION-linux-x86_64/bin" >> "$GITHUB_PATH"

- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
mkdir -p libs/$LIBRARY
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python3 tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY

- name: Build with the standard library module and int128 module, then test
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -G Ninja \
-DBOOST_INCLUDE_LIBRARIES=$LIBRARY \
-DBUILD_TESTING=ON \
-DBOOST_INT128_BUILD_MODULE=ON \
-DCMAKE_CXX_COMPILER=clang++-$LLVM_VERSION \
-DCMAKE_CXX_FLAGS="-stdlib=libc++" \
-DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=$IMPORT_STD_UUID \
-DCMAKE_CXX_STDLIB_MODULES_JSON=/usr/lib/llvm-$LLVM_VERSION/lib/libc++.modules.json \
..
cmake --build . --target tests
ctest --output-on-failure --no-tests=error
2 changes: 1 addition & 1 deletion include/boost/int128/bit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr int popcount(const uint12

namespace impl {

BOOST_INT128_HOST_DEVICE constexpr int popcount_impl(std::uint64_t x) noexcept
BOOST_INT128_TEST_EXPORT BOOST_INT128_HOST_DEVICE constexpr int popcount_impl(std::uint64_t x) noexcept
{
x = x - ((x >> 1U) & UINT64_C(0x5555555555555555));
x = (x & UINT64_C(0x3333333333333333)) + ((x >> 2U) & UINT64_C(0x3333333333333333));
Expand Down
5 changes: 4 additions & 1 deletion include/boost/int128/detail/clz.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ namespace boost {
namespace int128 {
namespace detail {

namespace impl {
// The whole impl namespace is exported when building the module for testing so
// the low-level bit helpers can be exercised directly; it is an ordinary
// namespace in every other build.
BOOST_INT128_TEST_EXPORT namespace impl {

#if !(defined(__CUDACC__) && defined(BOOST_INT128_ENABLE_CUDA))

Expand Down
34 changes: 28 additions & 6 deletions include/boost/int128/detail/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@
#ifndef BOOST_INT128_DETAIL_CONFIG_HPP
#define BOOST_INT128_DETAIL_CONFIG_HPP

// A handful of detail-namespace entities are exercised directly by the module
// test suite. BOOST_INT128_TEST_EXPORT exports them only when the module is built
// for testing (BOOST_INT128_EXPORT_TESTING), so the normal module API stays limited
// to the public interface. It expands to nothing in ordinary (header) builds.
#if defined(BOOST_INT128_BUILD_MODULE) && defined(BOOST_INT128_EXPORT_TESTING)
# define BOOST_INT128_TEST_EXPORT export
#else
# define BOOST_INT128_TEST_EXPORT
#endif

// The SYCL device target (spir64) has no native 128-bit integer, so force the portable
// code path on the device pass. This mirrors a user-supplied BOOST_INT128_NO_BUILTIN_INT128
// and keeps host/device selection consistent even though __x86_64__ stays defined on device.
Expand All @@ -25,19 +35,26 @@ namespace boost {
namespace int128 {
namespace detail {

// A module consumer receives these aliases from the import, so only declare them
// in ordinary builds and in the module interface unit itself; declaring them again
// in a consumer would give a second, distinct type and break overload resolution.
#if !defined(BOOST_INT128_BUILD_MODULE) || defined(BOOST_INT128_INTERFACE_UNIT)

// Avoids pedantic warnings
#ifdef __GNUC__

__extension__ using builtin_i128 = __int128 ;
__extension__ using builtin_u128 = unsigned __int128 ;
BOOST_INT128_TEST_EXPORT __extension__ using builtin_i128 = __int128 ;
BOOST_INT128_TEST_EXPORT __extension__ using builtin_u128 = unsigned __int128 ;

#else

using builtin_i128 = __int128 ;
using builtin_u128 = unsigned __int128;
BOOST_INT128_TEST_EXPORT using builtin_i128 = __int128 ;
BOOST_INT128_TEST_EXPORT using builtin_u128 = unsigned __int128;

#endif

#endif // declare builtin aliases

} // namespace detail
} // namespace int128
} // namespace boost
Expand All @@ -60,8 +77,13 @@ namespace boost {
namespace int128 {
namespace detail {

using builtin_i128 = std::_Signed128;
using builtin_u128 = std::_Unsigned128;
// See the note above: skip the re-declaration in a module consumer.
#if !defined(BOOST_INT128_BUILD_MODULE) || defined(BOOST_INT128_INTERFACE_UNIT)

BOOST_INT128_TEST_EXPORT using builtin_i128 = std::_Signed128;
BOOST_INT128_TEST_EXPORT using builtin_u128 = std::_Unsigned128;

#endif

} // namespace detail
} // namespace int128
Expand Down
21 changes: 17 additions & 4 deletions include/boost/int128/detail/int128_imp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1898,12 +1898,12 @@ BOOST_INT128_HOST_DEVICE constexpr int128_t operator+(const SignedInteger lhs, c
#if defined(BOOST_INT128_HAS_INT128) || defined(BOOST_INT128_HAS_MSVC_INT128)


BOOST_INT128_HOST_DEVICE BOOST_INT128_BUILTIN_CONSTEXPR int128_t operator+(const int128_t lhs, const detail::builtin_i128 rhs) noexcept
BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE BOOST_INT128_BUILTIN_CONSTEXPR int128_t operator+(const int128_t lhs, const detail::builtin_i128 rhs) noexcept
{
return detail::default_add(lhs, static_cast<int128_t>(rhs));
}

BOOST_INT128_HOST_DEVICE BOOST_INT128_BUILTIN_CONSTEXPR int128_t operator+(const detail::builtin_i128 lhs, const int128_t rhs) noexcept
BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE BOOST_INT128_BUILTIN_CONSTEXPR int128_t operator+(const detail::builtin_i128 lhs, const int128_t rhs) noexcept
{
return detail::default_add(rhs, static_cast<int128_t>(lhs));
}
Expand Down Expand Up @@ -2631,10 +2631,23 @@ template <bool b> constexpr bool numeric_limits_impl_i128<b>::has_infinity;
template <bool b> constexpr bool numeric_limits_impl_i128<b>::has_quiet_NaN;
template <bool b> constexpr bool numeric_limits_impl_i128<b>::has_signaling_NaN;

// These members were deprecated in C++23
#if ((!defined(_MSC_VER) && (__cplusplus <= 202002L)) || (defined(_MSC_VER) && (_MSVC_LANG <= 202002L)))
// These members were deprecated in C++23; suppress the deprecation warning rather
// than dropping the definitions.
#if defined(__GNUC__) && __cplusplus > 202002L
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable:4996)
#endif

template <bool b> constexpr std::float_denorm_style numeric_limits_impl_i128<b>::has_denorm;
template <bool b> constexpr bool numeric_limits_impl_i128<b>::has_denorm_loss;

#if defined(__GNUC__) && __cplusplus > 202002L
# pragma GCC diagnostic pop
#elif defined(_MSC_VER)
# pragma warning(pop)
#endif

template <bool b> constexpr std::float_round_style numeric_limits_impl_i128<b>::round_style;
Expand Down
17 changes: 17 additions & 0 deletions include/boost/int128/detail/literal_macros.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2022 Peter Dimov
// Copyright 2025 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt

#ifndef BOOST_INT128_DETAIL_LITERAL_MACROS_HPP
#define BOOST_INT128_DETAIL_LITERAL_MACROS_HPP

// Convenience macros for the user-defined literals. This header intentionally has
// no includes and declares nothing, so module consumers can pull it in on its own
// to obtain the macros (macros are never part of a module's exported interface).

#define BOOST_INT128_STRINGIFY(x) #x
#define BOOST_INT128_UINT128_C(x) boost::int128::literals::operator""_u128(BOOST_INT128_STRINGIFY(x))
#define BOOST_INT128_INT128_C(x) boost::int128::literals::operator""_i128(BOOST_INT128_STRINGIFY(x))

#endif // BOOST_INT128_DETAIL_LITERAL_MACROS_HPP
4 changes: 2 additions & 2 deletions include/boost/int128/detail/mini_from_chars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,12 @@ BOOST_INT128_HOST_DEVICE constexpr int from_chars_integer_impl(const char* first
}
} // namespace impl

BOOST_INT128_HOST_DEVICE constexpr int from_chars(const char* first, const char* last, uint128_t& value, int base = 10) noexcept
BOOST_INT128_TEST_EXPORT BOOST_INT128_HOST_DEVICE constexpr int from_chars(const char* first, const char* last, uint128_t& value, int base = 10) noexcept
{
return impl::from_chars_integer_impl<uint128_t, uint128_t>(first, last, value, base);
}

BOOST_INT128_HOST_DEVICE constexpr int from_chars(const char* first, const char* last, int128_t& value, int base = 10) noexcept
BOOST_INT128_TEST_EXPORT BOOST_INT128_HOST_DEVICE constexpr int from_chars(const char* first, const char* last, int128_t& value, int base = 10) noexcept
{
return impl::from_chars_integer_impl<int128_t, uint128_t>(first, last, value, base);
}
Expand Down
17 changes: 15 additions & 2 deletions include/boost/int128/detail/uint128_imp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2805,10 +2805,23 @@ template <bool b> constexpr bool numeric_limits_impl_u128<b>::has_infinity;
template <bool b> constexpr bool numeric_limits_impl_u128<b>::has_quiet_NaN;
template <bool b> constexpr bool numeric_limits_impl_u128<b>::has_signaling_NaN;

// These members were deprecated in C++23
#if ((!defined(_MSC_VER) && (__cplusplus <= 202002L)) || (defined(_MSC_VER) && (_MSVC_LANG <= 202002L)))
// These members were deprecated in C++23; suppress the deprecation warning rather
// than dropping the definitions.
#if defined(__GNUC__) && __cplusplus > 202002L
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable:4996)
#endif

template <bool b> constexpr std::float_denorm_style numeric_limits_impl_u128<b>::has_denorm;
template <bool b> constexpr bool numeric_limits_impl_u128<b>::has_denorm_loss;

#if defined(__GNUC__) && __cplusplus > 202002L
# pragma GCC diagnostic pop
#elif defined(_MSC_VER)
# pragma warning(pop)
#endif

template <bool b> constexpr std::float_round_style numeric_limits_impl_u128<b>::round_style;
Expand Down
3 changes: 3 additions & 0 deletions include/boost/int128/format.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
#include <boost/int128/detail/mini_to_chars.hpp>
#include <boost/int128/detail/config.hpp>
#include <boost/int128/int128.hpp>

#ifndef BOOST_INT128_BUILD_MODULE
#include <string>
#include <format>
#include <tuple>
#endif

#define BOOST_INT128_HAS_FORMAT

Expand Down
6 changes: 2 additions & 4 deletions include/boost/int128/literals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr int128_t operator ""_i128
return result;
}

BOOST_INT128_HOST_DEVICE constexpr int128_t operator ""_I128(const char* str) noexcept
BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr int128_t operator ""_I128(const char* str) noexcept
{
int128_t result {};
detail::from_chars(str, str + detail::strlen(str), result);
Expand All @@ -75,8 +75,6 @@ BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr int128_t operator ""_I128
} // namespace int128
} // namespace boost

#define BOOST_INT128_STRINGIFY(x) #x
#define BOOST_INT128_UINT128_C(x) boost::int128::literals::operator""_u128(BOOST_INT128_STRINGIFY(x))
#define BOOST_INT128_INT128_C(x) boost::int128::literals::operator""_i128(BOOST_INT128_STRINGIFY(x))
#include <boost/int128/detail/literal_macros.hpp>

#endif // BOOST_INT128_LITERALS_HPP
20 changes: 10 additions & 10 deletions include/boost/int128/numeric.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr uint128_t sub_sat(const u
# pragma warning(disable : 4146) // Unary minus applied to unsigned type
#endif

BOOST_INT128_HOST_DEVICE constexpr int128_t add_sat(const int128_t x, const int128_t y) noexcept
BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr int128_t add_sat(const int128_t x, const int128_t y) noexcept
{
// Detect overflow BEFORE the addition to avoid signed overflow UB.
// When both are non-negative: overflow iff x > max - y (subtraction safe: max - non_negative >= 0)
Expand All @@ -108,7 +108,7 @@ BOOST_INT128_HOST_DEVICE constexpr int128_t add_sat(const int128_t x, const int1
return x + y;
}

BOOST_INT128_HOST_DEVICE constexpr int128_t sub_sat(const int128_t x, const int128_t y) noexcept
BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr int128_t sub_sat(const int128_t x, const int128_t y) noexcept
{
// Detect overflow BEFORE the subtraction to avoid signed overflow UB.
// Positive overflow: x >= 0 and y < 0 and x > max + y (safe: max + negative < max)
Expand Down Expand Up @@ -247,7 +247,7 @@ BOOST_INT128_HOST_DEVICE constexpr TargetType saturate_cast(const int128_t value

namespace detail {

BOOST_INT128_HOST_DEVICE constexpr std::uint64_t gcd64(std::uint64_t x, std::uint64_t y) noexcept
BOOST_INT128_TEST_EXPORT BOOST_INT128_HOST_DEVICE constexpr std::uint64_t gcd64(std::uint64_t x, std::uint64_t y) noexcept
{
if (x == 0)
{
Expand Down Expand Up @@ -279,7 +279,7 @@ BOOST_INT128_HOST_DEVICE constexpr std::uint64_t gcd64(std::uint64_t x, std::uin

} // namespace detail

BOOST_INT128_HOST_DEVICE constexpr uint128_t gcd(uint128_t a, uint128_t b) noexcept
BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr uint128_t gcd(uint128_t a, uint128_t b) noexcept
{
// Base case
if (a == 0U)
Expand Down Expand Up @@ -316,7 +316,7 @@ BOOST_INT128_HOST_DEVICE constexpr uint128_t gcd(uint128_t a, uint128_t b) noexc
return uint128_t{0, g} << shift;
}

BOOST_INT128_HOST_DEVICE constexpr int128_t gcd(const int128_t a, const int128_t b) noexcept
BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr int128_t gcd(const int128_t a, const int128_t b) noexcept
{
return static_cast<int128_t>(gcd(static_cast<uint128_t>(abs(a)), static_cast<uint128_t>(abs(b))));
}
Expand All @@ -326,7 +326,7 @@ BOOST_INT128_HOST_DEVICE constexpr int128_t gcd(const int128_t a, const int128_t
// but very slow impl that we know works.
#if !(defined(_M_IX86) && !defined(_NDEBUG))

BOOST_INT128_HOST_DEVICE constexpr uint128_t lcm(const uint128_t a, const uint128_t b) noexcept
BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr uint128_t lcm(const uint128_t a, const uint128_t b) noexcept
{
if (a == 0U || b == 0U)
{
Expand All @@ -342,7 +342,7 @@ BOOST_INT128_HOST_DEVICE constexpr uint128_t lcm(const uint128_t a, const uint12

#else

BOOST_INT128_HOST_DEVICE constexpr uint128_t lcm(uint128_t a, uint128_t b) noexcept
BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr uint128_t lcm(uint128_t a, uint128_t b) noexcept
{
if (a == 0U || b == 0U)
{
Expand Down Expand Up @@ -376,12 +376,12 @@ BOOST_INT128_HOST_DEVICE constexpr uint128_t lcm(uint128_t a, uint128_t b) noexc

#endif

BOOST_INT128_HOST_DEVICE constexpr int128_t lcm(const int128_t a, const int128_t b) noexcept
BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr int128_t lcm(const int128_t a, const int128_t b) noexcept
{
return static_cast<int128_t>(lcm(static_cast<uint128_t>(abs(a)), static_cast<uint128_t>(abs(b))));
}

BOOST_INT128_HOST_DEVICE constexpr uint128_t midpoint(const uint128_t a, const uint128_t b) noexcept
BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr uint128_t midpoint(const uint128_t a, const uint128_t b) noexcept
{
// Bit manipulation formula works for unsigned integers
auto mid {(a & b) + ((a ^ b) >> 1)};
Expand All @@ -395,7 +395,7 @@ BOOST_INT128_HOST_DEVICE constexpr uint128_t midpoint(const uint128_t a, const u
return mid;
}

BOOST_INT128_HOST_DEVICE constexpr int128_t midpoint(const int128_t a, const int128_t b) noexcept
BOOST_INT128_EXPORT BOOST_INT128_HOST_DEVICE constexpr int128_t midpoint(const int128_t a, const int128_t b) noexcept
{
// For signed integers, we use a + (b - a) / 2 or a - (a - b) / 2
// The subtraction is done in unsigned arithmetic to handle overflow correctly
Expand Down
2 changes: 1 addition & 1 deletion include/boost/int128/utilities.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ BOOST_INT128_HOST_DEVICE constexpr uint128_t addmod(const uint128_t a, const uin
}

// Modular multiplication via shift-and-add for the full 128-bit modulus case
BOOST_INT128_HOST_DEVICE constexpr uint128_t mulmod_shift(uint128_t a, uint128_t b, const uint128_t m) noexcept
BOOST_INT128_TEST_EXPORT BOOST_INT128_HOST_DEVICE constexpr uint128_t mulmod_shift(uint128_t a, uint128_t b, const uint128_t m) noexcept
{
uint128_t result {0};

Expand Down
Loading
Loading