Skip to content

Commit

Permalink
_detail::Size, more generic ssize, SFINAE counted_view::end
Browse files Browse the repository at this point in the history
  • Loading branch information
OleErikPeistorpet committed Aug 31, 2023
1 parent 5151864 commit d4134e2
Show file tree
Hide file tree
Showing 9 changed files with 54 additions and 36 deletions.
14 changes: 14 additions & 0 deletions auxi/contiguous_iterator_to_ptr.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,20 @@ auto to_pointer_contiguous(std::move_iterator<Iterator> it) noexcept

namespace _detail
{
template< typename Range >
constexpr auto Size(Range && r)
-> decltype(r.size()) { return r.size(); }

template< typename Range, typename... None,
enable_if<
maybe_sized_sentinel_for< sentinel_t<Range>, iterator_t<Range> >::value
> = 0 >
constexpr auto Size(Range && r, None...)
-> decltype(end(r) - begin(r))
{ return end(r) - begin(r); }



template< typename T >
std::is_trivially_copyable<T> CanMemmoveArrays(T * /*dest*/, const T *);

Expand Down
4 changes: 2 additions & 2 deletions auxi/impl_algo.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,8 @@ namespace _detail

template< typename Range >
auto CountOrEnd(Range & r)
-> decltype( size_t(oel::ssize(r)) )
{ return size_t(oel::ssize(r)); }
-> decltype( static_cast<size_t>(_detail::Size(r)) )
{ return static_cast<size_t>(_detail::Size(r)); }
}

} // namespace oel
14 changes: 7 additions & 7 deletions auxi/range_algo_detail.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ namespace _detail
template< typename ContiguousIter, typename ContiguousIter2,
enable_if< can_memmove_with<ContiguousIter2, ContiguousIter>::value > = 0
>
ContiguousIter CopyUnsf(ContiguousIter const src, ptrdiff_t const n, ContiguousIter2 const dest)
ContiguousIter CopyUnsf(ContiguousIter const src, size_t const n, ContiguousIter2 const dest)
{
#if OEL_MEM_BOUND_DEBUG_LVL
if (n != 0)
Expand All @@ -61,10 +61,10 @@ namespace _detail
return src + n;
}

template< typename InputIter, typename Integral, typename RandomAccessIter, typename... None >
InputIter CopyUnsf(InputIter src, Integral const n, RandomAccessIter const dest, None...)
template< typename InputIter, typename RandomAccessIter, typename... None >
InputIter CopyUnsf(InputIter src, size_t const n, RandomAccessIter const dest, None...)
{
for (Integral i{}; i < n; ++i)
for (size_t i{}; i < n; ++i)
{
dest[i] = *src;
++src;
Expand Down Expand Up @@ -94,10 +94,10 @@ namespace _detail

template< typename SizedRange, typename RandomAccessRange >
auto CopyFit(SizedRange & src, RandomAccessRange & dest)
-> decltype( oel::ssize(src), bool() ) // better match if ssize(src) is well-formed (SFINAE)
-> decltype( _detail::Size(src), bool() ) // better match if Size(src) is well-formed (SFINAE)
{
auto const destSize = oel::ssize(dest);
auto n = oel::ssize(src);
auto n = as_unsigned(_detail::Size(src));
auto const destSize = as_unsigned(_detail::Size(dest));
bool const success{n <= destSize};
if (!success)
n = destSize;
Expand Down
5 changes: 4 additions & 1 deletion auxi/type_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,12 @@ using std::size_t;
using std::begin; using std::end;


//! Type returned by begin function (found by ADL)
//! Return type of begin function (found by ADL)
template< typename Range >
using iterator_t = decltype( begin(std::declval<Range &>()) );
//! Return type of end function (found by ADL)
template< typename Range >
using sentinel_t = decltype( end(std::declval<Range &>()) );

template< typename Iterator >
using iter_difference_t =
Expand Down
10 changes: 5 additions & 5 deletions range_algo.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,19 @@ struct copy_return
* @return `begin(source)` incremented by source size
* @pre If the ranges overlap, behavior is undefined (uses memcpy when possible)
*
* Requires that source has size() member or is an array, and that dest models RandomAccessIterator.
* Requires that `source.size()` or `end(source) - begin(source)` is valid, and that dest models random_access_iterator.
* To move instead of copy, pass `view::move(source)`. To mimic std::copy_n, use view::counted.
* (Views can be used for all functions taking a range as source) */
template< typename SizedInputRange, typename RandomAccessIter > inline
auto copy_unsafe(SizedInputRange && source, RandomAccessIter dest)
-> copy_return<decltype(begin(source))>
{ return {_detail::CopyUnsf(begin(source), oel::ssize(source), dest)}; }
{ return {_detail::CopyUnsf(begin(source), _detail::Size(source), dest)}; }
/**
* @brief Copies the elements in source range into dest range, throws std::out_of_range if dest is smaller than source
* @return `begin(source)` incremented by the number of elements in source
* @pre If the ranges overlap, behavior is undefined (uses memcpy when possible)
*
* Requires that source has size() member or is an array, and dest is a random_access_range (C++20 concept) */
* Requires that `source.size()` or `end(source) - begin(source)` is valid, and that dest models random_access_range. */
template< typename SizedInputRange, typename RandomAccessRange >
auto copy(SizedInputRange && source, RandomAccessRange && dest)
-> copy_return<decltype(begin(source))>;
Expand All @@ -76,7 +76,7 @@ auto copy(SizedInputRange && source, RandomAccessRange && dest)
* @return true if all elements were copied, false means truncation happened
* @pre If the ranges overlap, behavior is undefined (uses memcpy when possible)
*
* Requires that dest is a random_access_range (otherwise compilation will fail) */
* Requires that dest is a random_access_range (C++20 concept) */
template< typename InputRange, typename RandomAccessRange > inline
bool copy_fit(InputRange && source, RandomAccessRange && dest) { return _detail::CopyFit(source, dest); }

Expand Down Expand Up @@ -116,7 +116,7 @@ template< typename SizedInputRange, typename RandomAccessRange >
auto oel::copy(SizedInputRange && src, RandomAccessRange && dest)
-> copy_return<decltype(begin(src))>
{
if (oel::ssize(src) <= oel::ssize(dest))
if (as_unsigned(_detail::Size(src)) <= as_unsigned(_detail::Size(dest)))
return oel::copy_unsafe(src, begin(dest));
else
_detail::Throw::outOfRange("Too small dest oel::copy");
Expand Down
14 changes: 4 additions & 10 deletions range_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,6 @@ class basic_view
Sentinel _end;
};

//! Participates in overload resolution only if v.begin() can be subtracted from v.end()
template< typename Iterator, typename Sentinel,
enable_if< maybe_sized_sentinel_for<Sentinel, Iterator>::value > = 0
>
auto ssize(const basic_view<Iterator, Sentinel> & v)
-> decltype( v.end() - v.begin() )
{ return v.end() - v.begin(); }


//! Wrapper for iterator and size
template< typename Iterator, bool = iter_is_random_access<Iterator>::value >
Expand All @@ -76,8 +68,10 @@ class counted_view
constexpr counted_view(SizedRange & r) : _begin(oel::adl_begin(r)), _size(oel::ssize(r)) {}

constexpr Iterator begin() const OEL_ALWAYS_INLINE { return _begin; }

constexpr auto end() const { return _detail::SentinelAt(_begin, _size); }
//! Provided only if Iterator is random-access or special case
template< typename I = Iterator >
constexpr auto end() const
-> decltype( _detail::SentinelAt(std::declval<I>(), difference_type{}) ) { return _detail::SentinelAt(_begin, _size); }

constexpr size_type size() const noexcept OEL_ALWAYS_INLINE { return _size; }

Expand Down
2 changes: 1 addition & 1 deletion unit_test/dynarray_other_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ TEST(dynarrayOtherTest, oelDynarrWithStdAlloc)
MoveOnly::countToThrowOn = 0;
EXPECT_THROW( v.emplace_back(), TestException );
)
EXPECT_EQ(2, oel::ssize(v));
EXPECT_EQ(2, ssize(v));
EXPECT_TRUE(1.0 == *v[0]);
EXPECT_TRUE(2.0 == *v[1]);
}
Expand Down
11 changes: 11 additions & 0 deletions unit_test/util_gtest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,14 @@ TEST(utilTest, toPointerContiguous)
EXPECT_EQ(addr, result);
#endif
}

struct EmptyRandomAccessRange {};

int * begin(EmptyRandomAccessRange) { return {}; }
int * end(EmptyRandomAccessRange) { return {}; }

TEST(utilTest, detailSize_rangeNoMember)
{
EmptyRandomAccessRange r;
EXPECT_EQ(0, oel::_detail::Size(r));
}
16 changes: 6 additions & 10 deletions util.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,16 @@ template< typename T > OEL_ALWAYS_INLINE
constexpr std::make_unsigned_t<T> as_unsigned(T val) noexcept { return std::make_unsigned_t<T>(val); }


//! Same as std::ssize, except that non-const `r.size()` is supported
//! More generic than std::ssize, close to std::ranges::ssize
template< typename SizedRangeLike >
constexpr auto ssize(SizedRangeLike && r)
-> std::common_type_t< ptrdiff_t, std::make_signed_t<decltype(r.size())> >
-> std::common_type_t< ptrdiff_t, decltype(as_signed( _detail::Size(r) )) >
{
using S = std::common_type_t< ptrdiff_t, std::make_signed_t<decltype(r.size())> >;
return static_cast<S>(r.size());
return std::common_type_t< ptrdiff_t, decltype(as_signed( _detail::Size(r) )) >(_detail::Size(r));
}
//! Equivalent to std::ssize, array overload
template< typename T, ptrdiff_t Size > OEL_ALWAYS_INLINE
constexpr ptrdiff_t ssize(const T(&)[Size]) noexcept { return Size; }


/** @brief Check if index is valid (can be used with operator[]) for array or other container-like object
/** @brief Check if index is valid (can be used with operator[]) for sized_range (std concept) or similar
*
* Negative index should give false result. However, this is not ensured if the index type holds more
* bits than `int`, yet the maximum value of index type is less than the number of elements in r.
Expand Down Expand Up @@ -136,7 +132,7 @@ namespace _detail
template< typename Integral, typename SizedRange >
constexpr bool oel::index_valid(const SizedRange & r, Integral index)
{
using T = decltype(oel::ssize(r));
using T = decltype(_detail::Size(r));
using NeitherIsBig = bool_constant<sizeof(T) < sizeof(_detail::BigUint) and sizeof index < sizeof(_detail::BigUint)>;
return _detail::IndexValid(as_unsigned(oel::ssize(r)), index, NeitherIsBig{});
return _detail::IndexValid(as_unsigned(_detail::Size(r)), index, NeitherIsBig{});
}

0 comments on commit d4134e2

Please sign in to comment.