Skip to content

Commit

Permalink
libstdc++: Make incrementable<__int128> satisfied in strict mode
Browse files Browse the repository at this point in the history
This adds specializations of std::incrementable_traits so that 128-bit
integers are always considered incrementable (and therefore usable with
std::ranges::iota_view) even when they don't satisfy std::integral.

libstdc++-v3/ChangeLog:

	* include/bits/iterator_concepts.h [__STRICT_ANSI__]
	(incrementable_traits<__int128>): Define specialization.
	(incrementable_traits<unsigned __int128>): Likewise.
	* testsuite/std/ranges/iota/96042.cc: Test iota_view with
	__int128.
  • Loading branch information
jwakely committed Aug 20, 2020
1 parent 300ef2f commit 5e9ad28
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 1 deletion.
11 changes: 11 additions & 0 deletions libstdc++-v3/include/bits/iterator_concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
= make_signed_t<decltype(std::declval<_Tp>() - std::declval<_Tp>())>;
};

#if defined __STRICT_ANSI__ && defined __SIZEOF_INT128__
// __int128 is incrementable even if !integral<__int128>
template<>
struct incrementable_traits<__int128>
{ using difference_type = __int128; };

template<>
struct incrementable_traits<unsigned __int128>
{ using difference_type = __int128; };
#endif

namespace __detail
{
// An iterator such that iterator_traits<_Iter> names a specialization
Expand Down
28 changes: 27 additions & 1 deletion libstdc++-v3/testsuite/std/ranges/iota/96042.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,33 @@ void
test01()
{
// PR libstdc++/96042
using V = std::ranges::iota_view<long long, int>;
using V = std::ranges::iota_view<long long, long long>;

// In strict -std=c++20 mode there is no integer wider than long long,
// so V's difference type is an integer-class type, [iterator.concept.winc].
// In practice this is either __int128 or __detail::__max_diff_type.
using D = std::ranges::range_difference_t<V>;
// Ensure that numeric_limits is correctly specialized for the type.
using L = std::numeric_limits<D>;
static_assert( L::is_specialized );
static_assert( L::is_signed );
static_assert( L::is_integer );
static_assert( L::is_exact );
static_assert( L::digits > std::numeric_limits<long long>::digits );
static_assert( L::digits10 == static_cast<int>(L::digits * 0.30103) );
static_assert( L::min() == (D(1) << L::digits) );
static_assert( L::max() == ~L::min() );
static_assert( L::lowest() == L::min() );
}

#ifdef __SIZEOF_INT128__
void
test02()
{
// When the target supports __int128 it can be used in iota_view
// even in strict mode where !integral<__int128>.
using V = std::ranges::iota_view<__int128, __int128>;
using D = std::ranges::range_difference_t<V>; // __detail::__max_diff_type
using L = std::numeric_limits<D>;
static_assert( L::is_specialized );
static_assert( L::is_signed );
Expand All @@ -37,3 +62,4 @@ test01()
static_assert( L::max() == ~L::min() );
static_assert( L::lowest() == L::min() );
}
#endif

0 comments on commit 5e9ad28

Please sign in to comment.