mirror of
https://github.com/boostorg/stl_interfaces.git
synced 2026-01-19 04:42:12 +00:00
Add more robust view_interface tests.
This commit is contained in:
@@ -65,6 +65,8 @@ namespace boost { namespace stl_interfaces {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO:
|
||||
|
||||
// Container requirements:
|
||||
// mutable begin/end -> const begin/end,cbegin/cend
|
||||
// c1 == c2 -> c1 != c2
|
||||
@@ -105,7 +107,7 @@ namespace boost { namespace stl_interfaces {
|
||||
/** A CRTP template that one may derive from to make it easier to define
|
||||
container types. */
|
||||
template<typename Derived, bool Contiguous = discontiguous>
|
||||
struct container_interface : view_interface<Derived, Contiguous>
|
||||
struct container_interface : view_interface<Derived, Contiguous, true>
|
||||
{
|
||||
template<typename D = Derived>
|
||||
constexpr auto begin() const
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace boost { namespace stl_interfaces {
|
||||
/** An enumeration used to indicate whether the underlying data have a
|
||||
contiguous layout when instantiating `view_interface` and
|
||||
`container_interface`. */
|
||||
enum element_layout : bool { discontiguous, contiguous };
|
||||
enum element_layout : bool { discontiguous = false, contiguous = true };
|
||||
|
||||
namespace detail {
|
||||
template<typename... T>
|
||||
|
||||
@@ -55,10 +55,15 @@ namespace boost { namespace stl_interfaces {
|
||||
[view.interface] in the C++ standard). */
|
||||
template<
|
||||
typename Derived,
|
||||
bool Contiguous = discontiguous,
|
||||
bool Contiguous = discontiguous
|
||||
#ifndef BOOST_STL_INTERFACES_DOXYGEN
|
||||
,
|
||||
bool SuppressBoolConversion = false,
|
||||
typename E = std::enable_if_t<
|
||||
std::is_class<Derived>::value &&
|
||||
std::is_same<Derived, std::remove_cv_t<Derived>>::value>>
|
||||
std::is_same<Derived, std::remove_cv_t<Derived>>::value>
|
||||
#endif
|
||||
>
|
||||
struct view_interface
|
||||
{
|
||||
#ifndef BOOST_STL_INTERFACES_DOXYGEN
|
||||
@@ -95,7 +100,9 @@ namespace boost { namespace stl_interfaces {
|
||||
|
||||
template<
|
||||
typename D = Derived,
|
||||
typename R = decltype(std::declval<D &>().empty())>
|
||||
typename R = std::enable_if_t<
|
||||
!SuppressBoolConversion,
|
||||
decltype(std::declval<D &>().empty())>>
|
||||
constexpr explicit
|
||||
operator R() noexcept(noexcept(std::declval<D &>().empty()))
|
||||
{
|
||||
@@ -103,7 +110,9 @@ namespace boost { namespace stl_interfaces {
|
||||
}
|
||||
template<
|
||||
typename D = Derived,
|
||||
typename R = decltype(std::declval<D &>().empty())>
|
||||
typename R = std::enable_if_t<
|
||||
!SuppressBoolConversion,
|
||||
decltype(std::declval<D &>().empty())>>
|
||||
constexpr explicit operator bool() const
|
||||
noexcept(noexcept(std::declval<D &>().empty()))
|
||||
{
|
||||
@@ -115,7 +124,7 @@ namespace boost { namespace stl_interfaces {
|
||||
bool C = Contiguous,
|
||||
typename Enable = std::enable_if_t<C>>
|
||||
constexpr auto data() noexcept(noexcept(std::declval<D &>().begin()))
|
||||
-> decltype(std::declval<D &>().begin())
|
||||
-> decltype(std::addressof(*std::declval<D &>().begin()))
|
||||
{
|
||||
return std::addressof(*derived().begin());
|
||||
}
|
||||
@@ -125,7 +134,7 @@ namespace boost { namespace stl_interfaces {
|
||||
typename Enable = std::enable_if_t<C>>
|
||||
constexpr auto data() const
|
||||
noexcept(noexcept(std::declval<D &>().begin()))
|
||||
-> decltype(std::declval<D &>().begin())
|
||||
-> decltype(std::addressof(*std::declval<D &>().begin()))
|
||||
{
|
||||
return std::addressof(*derived().begin());
|
||||
}
|
||||
@@ -149,14 +158,14 @@ namespace boost { namespace stl_interfaces {
|
||||
constexpr auto front() noexcept(noexcept(*std::declval<D &>().begin()))
|
||||
-> decltype(*std::declval<D &>().begin())
|
||||
{
|
||||
*derived().begin();
|
||||
return *derived().begin();
|
||||
}
|
||||
template<typename D = Derived>
|
||||
constexpr auto front() const
|
||||
noexcept(noexcept(*std::declval<D &>().begin()))
|
||||
-> decltype(*std::declval<D &>().begin())
|
||||
{
|
||||
*derived().begin();
|
||||
return *derived().begin();
|
||||
}
|
||||
|
||||
template<
|
||||
|
||||
@@ -401,3 +401,96 @@ TEST(bidirectional, const_std_copy)
|
||||
std::greater<>{}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////
|
||||
// view_interface //
|
||||
////////////////////
|
||||
#include "view_tests.hpp"
|
||||
|
||||
TEST(bidirectional, basic_subrange)
|
||||
{
|
||||
basic_bidirectional_iter first(ints.data());
|
||||
basic_bidirectional_iter last(ints.data() + ints.size());
|
||||
|
||||
auto r = range<boost::stl_interfaces::discontiguous>(first, last);
|
||||
auto empty = range<boost::stl_interfaces::discontiguous>(first, first);
|
||||
|
||||
// range begin/end
|
||||
{
|
||||
std::array<int, 10> ints_copy;
|
||||
std::copy(r.begin(), r.end(), ints_copy.begin());
|
||||
EXPECT_EQ(ints_copy, ints);
|
||||
|
||||
EXPECT_EQ(empty.begin(), empty.end());
|
||||
}
|
||||
|
||||
// empty/op bool
|
||||
{
|
||||
EXPECT_FALSE(r.empty());
|
||||
EXPECT_TRUE(r);
|
||||
|
||||
EXPECT_TRUE(empty.empty());
|
||||
EXPECT_FALSE(empty);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_FALSE(cr.empty());
|
||||
EXPECT_TRUE(cr);
|
||||
|
||||
auto const cempty = empty;
|
||||
EXPECT_TRUE(cempty.empty());
|
||||
EXPECT_FALSE(cempty);
|
||||
}
|
||||
|
||||
#if 0 // TODO: COMPILE-FAIL test for this.
|
||||
// data
|
||||
{
|
||||
EXPECT_NE(r.data(), nullptr);
|
||||
EXPECT_EQ(r.data()[2], 2);
|
||||
|
||||
EXPECT_NE(empty.data(), nullptr);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_NE(cr.data(), nullptr);
|
||||
EXPECT_EQ(cr.data()[2], 2);
|
||||
|
||||
auto const cempty = empty;
|
||||
EXPECT_NE(cempty.data(), nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0 // TODO: COMPILE-FAIL test for this.
|
||||
// size
|
||||
{
|
||||
EXPECT_EQ(r.size(), 10u);
|
||||
|
||||
EXPECT_EQ(empty.size(), 0u);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_EQ(cr.size(), 10u);
|
||||
|
||||
auto const cempty = empty;
|
||||
EXPECT_EQ(cempty.size(), 0u);
|
||||
}
|
||||
#endif
|
||||
|
||||
// front/back
|
||||
{
|
||||
EXPECT_EQ(r.front(), 0);
|
||||
EXPECT_EQ(r.back(), 9);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_EQ(cr.front(), 0);
|
||||
EXPECT_EQ(cr.back(), 9);
|
||||
}
|
||||
|
||||
#if 0 // TODO: COMPILE-FAIL test for this.
|
||||
// op[]
|
||||
{
|
||||
EXPECT_EQ(r[2], 2);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_EQ(cr[2], 2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -220,3 +220,97 @@ TEST(forward, const_std_copy)
|
||||
EXPECT_TRUE(std::binary_search(first, last, 3));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////
|
||||
// view_interface //
|
||||
////////////////////
|
||||
#include "view_tests.hpp"
|
||||
|
||||
TEST(forward, basic_subrange)
|
||||
{
|
||||
basic_forward_iter first(ints.data());
|
||||
basic_forward_iter last(ints.data() + ints.size());
|
||||
|
||||
auto r = range<boost::stl_interfaces::discontiguous>(first, last);
|
||||
auto empty = range<boost::stl_interfaces::discontiguous>(first, first);
|
||||
|
||||
// range begin/end
|
||||
{
|
||||
std::array<int, 10> ints_copy;
|
||||
std::copy(r.begin(), r.end(), ints_copy.begin());
|
||||
EXPECT_EQ(ints_copy, ints);
|
||||
|
||||
EXPECT_EQ(empty.begin(), empty.end());
|
||||
}
|
||||
|
||||
// empty/op bool
|
||||
{
|
||||
EXPECT_FALSE(r.empty());
|
||||
EXPECT_TRUE(r);
|
||||
|
||||
EXPECT_TRUE(empty.empty());
|
||||
EXPECT_FALSE(empty);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_FALSE(cr.empty());
|
||||
EXPECT_TRUE(cr);
|
||||
|
||||
auto const cempty = empty;
|
||||
EXPECT_TRUE(cempty.empty());
|
||||
EXPECT_FALSE(cempty);
|
||||
}
|
||||
|
||||
#if 0 // TODO: COMPILE-FAIL test for this.
|
||||
// data
|
||||
{
|
||||
EXPECT_NE(r.data(), nullptr);
|
||||
EXPECT_EQ(r.data()[2], 2);
|
||||
|
||||
EXPECT_NE(empty.data(), nullptr);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_NE(cr.data(), nullptr);
|
||||
EXPECT_EQ(cr.data()[2], 2);
|
||||
|
||||
auto const cempty = empty;
|
||||
EXPECT_NE(cempty.data(), nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0 // TODO: COMPILE-FAIL test for this.
|
||||
// size
|
||||
{
|
||||
EXPECT_EQ(r.size(), 10u);
|
||||
|
||||
EXPECT_EQ(empty.size(), 0u);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_EQ(cr.size(), 10u);
|
||||
|
||||
auto const cempty = empty;
|
||||
EXPECT_EQ(cempty.size(), 0u);
|
||||
}
|
||||
#endif
|
||||
|
||||
// front/back
|
||||
{
|
||||
EXPECT_EQ(r.front(), 0);
|
||||
#if 0 // TODO: COMPILE-FAIL test for this.
|
||||
EXPECT_EQ(r.back(), 9);
|
||||
#endif
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_EQ(cr.front(), 0);
|
||||
}
|
||||
|
||||
#if 0 // TODO: COMPILE-FAIL test for this.
|
||||
// op[]
|
||||
{
|
||||
EXPECT_EQ(r[2], 2);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_EQ(cr[2], 2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -282,3 +282,97 @@ TEST(input, const_std_copy)
|
||||
EXPECT_EQ(firsts_copy, ints);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////
|
||||
// view_interface //
|
||||
////////////////////
|
||||
#include "view_tests.hpp"
|
||||
|
||||
TEST(input, basic_subrange)
|
||||
{
|
||||
basic_input_iter first(ints.data());
|
||||
basic_input_iter last(ints.data() + ints.size());
|
||||
|
||||
auto r = range<boost::stl_interfaces::discontiguous>(first, last);
|
||||
auto empty = range<boost::stl_interfaces::discontiguous>(first, first);
|
||||
|
||||
// range begin/end
|
||||
{
|
||||
std::array<int, 10> ints_copy;
|
||||
std::copy(r.begin(), r.end(), ints_copy.begin());
|
||||
EXPECT_EQ(ints_copy, ints);
|
||||
|
||||
EXPECT_EQ(empty.begin(), empty.end());
|
||||
}
|
||||
|
||||
// empty/op bool
|
||||
{
|
||||
EXPECT_FALSE(r.empty());
|
||||
EXPECT_TRUE(r);
|
||||
|
||||
EXPECT_TRUE(empty.empty());
|
||||
EXPECT_FALSE(empty);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_FALSE(cr.empty());
|
||||
EXPECT_TRUE(cr);
|
||||
|
||||
auto const cempty = empty;
|
||||
EXPECT_TRUE(cempty.empty());
|
||||
EXPECT_FALSE(cempty);
|
||||
}
|
||||
|
||||
#if 0 // TODO: COMPILE-FAIL test for this.
|
||||
// data
|
||||
{
|
||||
EXPECT_NE(r.data(), nullptr);
|
||||
EXPECT_EQ(r.data()[2], 2);
|
||||
|
||||
EXPECT_NE(empty.data(), nullptr);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_NE(cr.data(), nullptr);
|
||||
EXPECT_EQ(cr.data()[2], 2);
|
||||
|
||||
auto const cempty = empty;
|
||||
EXPECT_NE(cempty.data(), nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0 // TODO: COMPILE-FAIL test for this.
|
||||
// size
|
||||
{
|
||||
EXPECT_EQ(r.size(), 10u);
|
||||
|
||||
EXPECT_EQ(empty.size(), 0u);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_EQ(cr.size(), 10u);
|
||||
|
||||
auto const cempty = empty;
|
||||
EXPECT_EQ(cempty.size(), 0u);
|
||||
}
|
||||
#endif
|
||||
|
||||
// front/back
|
||||
{
|
||||
EXPECT_EQ(r.front(), 0);
|
||||
#if 0 // TODO: COMPILE-FAIL test for this.
|
||||
EXPECT_EQ(r.back(), 9);
|
||||
#endif
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_EQ(cr.front(), 0);
|
||||
}
|
||||
|
||||
#if 0 // TODO: COMPILE-FAIL test for this.
|
||||
// op[]
|
||||
{
|
||||
EXPECT_EQ(r[2], 2);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_EQ(cr[2], 2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -716,3 +716,156 @@ TEST(random_access, zip)
|
||||
std::equal(first, last, udt_tuples.begin(), udt_tuples.end()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////
|
||||
// view_interface //
|
||||
////////////////////
|
||||
#include "view_tests.hpp"
|
||||
|
||||
TEST(random_access, basic_subrange)
|
||||
{
|
||||
basic_random_access_iter first(ints.data());
|
||||
basic_random_access_iter last(ints.data() + ints.size());
|
||||
|
||||
auto r = range<boost::stl_interfaces::contiguous>(first, last);
|
||||
auto empty = range<boost::stl_interfaces::contiguous>(first, first);
|
||||
|
||||
// range begin/end
|
||||
{
|
||||
std::array<int, 10> ints_copy;
|
||||
std::copy(r.begin(), r.end(), ints_copy.begin());
|
||||
EXPECT_EQ(ints_copy, ints);
|
||||
|
||||
EXPECT_EQ(empty.begin(), empty.end());
|
||||
}
|
||||
|
||||
// empty/op bool
|
||||
{
|
||||
EXPECT_FALSE(r.empty());
|
||||
EXPECT_TRUE(r);
|
||||
|
||||
EXPECT_TRUE(empty.empty());
|
||||
EXPECT_FALSE(empty);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_FALSE(cr.empty());
|
||||
EXPECT_TRUE(cr);
|
||||
|
||||
auto const cempty = empty;
|
||||
EXPECT_TRUE(cempty.empty());
|
||||
EXPECT_FALSE(cempty);
|
||||
}
|
||||
|
||||
// data
|
||||
{
|
||||
EXPECT_NE(r.data(), nullptr);
|
||||
EXPECT_EQ(r.data()[2], 2);
|
||||
|
||||
EXPECT_NE(empty.data(), nullptr);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_NE(cr.data(), nullptr);
|
||||
EXPECT_EQ(cr.data()[2], 2);
|
||||
|
||||
auto const cempty = empty;
|
||||
EXPECT_NE(cempty.data(), nullptr);
|
||||
}
|
||||
|
||||
// size
|
||||
{
|
||||
EXPECT_EQ(r.size(), 10u);
|
||||
|
||||
EXPECT_EQ(empty.size(), 0u);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_EQ(cr.size(), 10u);
|
||||
|
||||
auto const cempty = empty;
|
||||
EXPECT_EQ(cempty.size(), 0u);
|
||||
}
|
||||
|
||||
// front/back
|
||||
{
|
||||
EXPECT_EQ(r.front(), 0);
|
||||
EXPECT_EQ(r.back(), 9);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_EQ(cr.front(), 0);
|
||||
EXPECT_EQ(cr.back(), 9);
|
||||
}
|
||||
|
||||
// op[]
|
||||
{
|
||||
EXPECT_EQ(r[2], 2);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_EQ(cr[2], 2);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(random_access, zip_subrange)
|
||||
{
|
||||
zip_iter first(ints.data(), ones.data());
|
||||
zip_iter last(ints.data() + ints.size(), ones.data() + ones.size());
|
||||
|
||||
auto r = range<boost::stl_interfaces::discontiguous>(first, last);
|
||||
auto empty = range<boost::stl_interfaces::discontiguous>(first, first);
|
||||
|
||||
// range begin/end
|
||||
{
|
||||
EXPECT_TRUE(std::equal(first, last, tuples.begin(), tuples.end()));
|
||||
}
|
||||
|
||||
// empty/op bool
|
||||
{
|
||||
EXPECT_FALSE(r.empty());
|
||||
EXPECT_TRUE(r);
|
||||
|
||||
EXPECT_TRUE(empty.empty());
|
||||
EXPECT_FALSE(empty);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_FALSE(cr.empty());
|
||||
EXPECT_TRUE(cr);
|
||||
|
||||
auto const cempty = empty;
|
||||
EXPECT_TRUE(cempty.empty());
|
||||
EXPECT_FALSE(cempty);
|
||||
}
|
||||
|
||||
// size
|
||||
{
|
||||
EXPECT_EQ(r.size(), 10u);
|
||||
|
||||
EXPECT_EQ(empty.size(), 0u);
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_EQ(cr.size(), 10u);
|
||||
|
||||
auto const cempty = empty;
|
||||
EXPECT_EQ(cempty.size(), 0u);
|
||||
}
|
||||
|
||||
// front/back
|
||||
{
|
||||
EXPECT_EQ(r.front(), (std::tuple<int, int>(0, 1)));
|
||||
EXPECT_EQ(r.back(), (std::tuple<int, int>(9, 1)));
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_EQ(cr.front(), (std::tuple<int, int>(0, 1)));
|
||||
EXPECT_EQ(cr.back(), (std::tuple<int, int>(9, 1)));
|
||||
}
|
||||
|
||||
// op[]
|
||||
{
|
||||
EXPECT_EQ(r[2], (std::tuple<int, int>(2, 1)));
|
||||
|
||||
auto const cr = r;
|
||||
EXPECT_EQ(cr[2], (std::tuple<int, int>(2, 1)));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: COMPILE-FAIL test that .data does not work on a discontiguous iterator.
|
||||
// TODO: COMPILE-FAIL test that .back does not work when common_range<> is false.
|
||||
// TODO: Document that proxy iterators are inherently discontiguous.
|
||||
|
||||
29
test/view_tests.hpp
Normal file
29
test/view_tests.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef BOOST_STL_INTERFACES_VIEW_TESTING_HPP
|
||||
#define BOOST_STL_INTERFACES_VIEW_TESTING_HPP
|
||||
|
||||
#include <boost/stl_interfaces/view_interface.hpp>
|
||||
|
||||
|
||||
template<typename Iterator, typename Sentinel, bool Contiguous>
|
||||
struct subrange
|
||||
: boost::stl_interfaces::
|
||||
view_interface<subrange<Iterator, Sentinel, Contiguous>, Contiguous>
|
||||
{
|
||||
subrange() = default;
|
||||
constexpr subrange(Iterator it, Sentinel s) : first_(it), last_(s) {}
|
||||
|
||||
constexpr auto begin() const { return first_; }
|
||||
constexpr auto end() const { return last_; }
|
||||
|
||||
private:
|
||||
Iterator first_;
|
||||
Sentinel last_;
|
||||
};
|
||||
|
||||
template<bool Contiguous, typename Iterator, typename Sentinel>
|
||||
auto range(Iterator i, Sentinel s)
|
||||
{
|
||||
return subrange<Iterator, Sentinel, Contiguous>(i, s);
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user