Add more robust view_interface tests.

This commit is contained in:
Zach Laine
2019-08-14 01:37:34 -05:00
parent cca6c86e9c
commit cd3caec37d
8 changed files with 484 additions and 10 deletions

View File

@@ -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

View File

@@ -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>

View File

@@ -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<

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
View 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