// Copyright (C) 2019 T. Zachary Laine // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include "ill_formed.hpp" #include #include #include #include // Just like std::array, except for the 0-size specialization, and the fact // that the base class makes brace-initialization wonky. template struct array : boost::stl_interfaces:: container_interface, boost::stl_interfaces::contiguous> { using value_type = T; using pointer = T *; using const_pointer = T const *; using reference = value_type &; using const_reference = value_type const &; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using iterator = T *; using const_iterator = T const *; using reverse_iterator = boost::stl_interfaces::reverse_iterator; using const_reverse_iterator = boost::stl_interfaces::reverse_iterator; void fill(T const & x) { std::fill(begin(), end(), x); } iterator begin() noexcept { return elements_; } iterator end() noexcept { return elements_ + N; } size_type max_size() const noexcept { return N; } void swap(array & other) { using std::swap; T * element = elements_; for (auto & x : other) { swap(*element++, x); } } using base_type = boost::stl_interfaces:: container_interface, boost::stl_interfaces::contiguous>; using base_type::begin; using base_type::end; friend bool operator==(array const & lhs, array const & rhs) { return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); } friend bool operator<(array const & lhs, array const & rhs) { auto const iters = std::mismatch(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); if (iters.second == rhs.end()) return false; if (iters.first == lhs.end()) return true; return *iters.first < *iters.second; } T elements_[N]; }; using arr_type = array; TEST(array, comparisons) { arr_type sm; sm[0] = 1; sm[1] = 2; sm[2] = 3; sm[3] = 0; sm[4] = 0; arr_type md; md[0] = 1; md[1] = 2; md[2] = 3; md[3] = 4; md[4] = 0; arr_type lg; lg[0] = 1; lg[1] = 2; lg[2] = 3; lg[3] = 4; lg[4] = 5; EXPECT_TRUE(sm == sm); EXPECT_FALSE(sm == md); EXPECT_FALSE(sm == lg); EXPECT_FALSE(sm < sm); EXPECT_TRUE(sm < md); EXPECT_TRUE(sm < lg); EXPECT_TRUE(sm <= sm); EXPECT_TRUE(sm <= md); EXPECT_TRUE(sm <= lg); EXPECT_FALSE(sm > sm); EXPECT_FALSE(sm > md); EXPECT_FALSE(sm > lg); EXPECT_TRUE(sm >= sm); EXPECT_FALSE(sm >= md); EXPECT_FALSE(sm >= lg); EXPECT_FALSE(md == sm); EXPECT_TRUE(md == md); EXPECT_FALSE(md == lg); EXPECT_FALSE(md < sm); EXPECT_FALSE(md < md); EXPECT_TRUE(md < lg); EXPECT_FALSE(md <= sm); EXPECT_TRUE(md <= md); EXPECT_TRUE(md <= lg); EXPECT_TRUE(md > sm); EXPECT_FALSE(md > md); EXPECT_FALSE(md > lg); EXPECT_TRUE(md >= sm); EXPECT_TRUE(md >= md); EXPECT_FALSE(md >= lg); EXPECT_FALSE(lg == sm); EXPECT_FALSE(lg == md); EXPECT_TRUE(lg == lg); EXPECT_FALSE(lg < sm); EXPECT_FALSE(lg < md); EXPECT_FALSE(lg < lg); EXPECT_FALSE(lg <= sm); EXPECT_FALSE(lg <= md); EXPECT_TRUE(lg <= lg); EXPECT_TRUE(lg > sm); EXPECT_TRUE(lg > md); EXPECT_FALSE(lg > lg); EXPECT_TRUE(lg >= sm); EXPECT_TRUE(lg >= md); EXPECT_TRUE(lg >= lg); } TEST(array, swap) { { arr_type v1; v1[0] = 3; v1[1] = 4; v1[2] = 0; v1[3] = 0; v1[4] = 0; arr_type v2; v2[0] = 4; v2[1] = 3; v2[2] = 0; v2[3] = 0; v2[4] = 0; arr_type const v1_copy = v1; arr_type const v2_copy = v2; static_assert(std::is_same::value, ""); static_assert(std::is_same::value, ""); v1.swap(v2); EXPECT_EQ(v1, v2_copy); EXPECT_EQ(v2, v1_copy); } { arr_type v1; v1[0] = 3; v1[1] = 4; v1[2] = 0; v1[3] = 0; v1[4] = 0; arr_type v2; v2[0] = 4; v2[1] = 3; v2[2] = 0; v2[3] = 0; v2[4] = 0; arr_type const v1_copy = v1; arr_type const v2_copy = v2; swap(v1, v2); EXPECT_EQ(v1, v2_copy); EXPECT_EQ(v2, v1_copy); } } template using writable_iter_t = decltype( *std::declval() = std::declval::value_type>()); static_assert( !ill_formed().begin())>:: value, ""); static_assert( !ill_formed().end())>:: value, ""); static_assert( ill_formed< writable_iter_t, decltype(std::declval().begin())>::value, ""); static_assert( ill_formed< writable_iter_t, decltype(std::declval().end())>::value, ""); static_assert( ill_formed().cbegin())>:: value, ""); static_assert( ill_formed().cend())>:: value, ""); static_assert( ill_formed< writable_iter_t, decltype(std::declval().rbegin())>::value, ""); static_assert( ill_formed< writable_iter_t, decltype(std::declval().rend())>::value, ""); static_assert( ill_formed< writable_iter_t, decltype(std::declval().crbegin())>::value, ""); static_assert( ill_formed().crend())>:: value, ""); TEST(array, iterators) { arr_type v0; v0[0] = 3; v0[1] = 2; v0[2] = 1; v0[3] = 0; v0[4] = 0; { arr_type v = v0; static_assert( std::is_same::value, ""); static_assert( std::is_same::value, ""); static_assert( std::is_same::value, ""); static_assert( std::is_same::value, ""); static_assert( std::is_same:: value, ""); static_assert( std::is_same:: value, ""); static_assert( std::is_same< decltype(v.crbegin()), arr_type::const_reverse_iterator>::value, ""); static_assert( std::is_same< decltype(v.crbegin()), arr_type::const_reverse_iterator>::value, ""); std::array const a = {{3, 2, 1, 0, 0}}; std::array const ra = {{0, 0, 1, 2, 3}}; EXPECT_TRUE(std::equal(v.begin(), v.end(), a.begin(), a.end())); EXPECT_TRUE(std::equal(v.cbegin(), v.cend(), a.begin(), a.end())); EXPECT_TRUE(std::equal(v.rbegin(), v.rend(), ra.begin(), ra.end())); EXPECT_TRUE(std::equal(v.crbegin(), v.crend(), ra.begin(), ra.end())); arr_type v2; v2[0] = 8; v2[1] = 2; v2[2] = 1; v2[3] = 0; v2[4] = 9; *v.begin() = 8; *v.rbegin() = 9; EXPECT_EQ(v, v2); } { arr_type const v = v0; static_assert( std::is_same::value, ""); static_assert( std::is_same::value, ""); static_assert( std::is_same::value, ""); static_assert( std::is_same::value, ""); static_assert( std::is_same< decltype(v.rbegin()), arr_type::const_reverse_iterator>::value, ""); static_assert( std::is_same< decltype(v.rbegin()), arr_type::const_reverse_iterator>::value, ""); static_assert( std::is_same< decltype(v.crbegin()), arr_type::const_reverse_iterator>::value, ""); static_assert( std::is_same< decltype(v.crbegin()), arr_type::const_reverse_iterator>::value, ""); std::array const a = {{3, 2, 1, 0, 0}}; std::array const ra = {{0, 0, 1, 2, 3}}; EXPECT_TRUE(std::equal(v.begin(), v.end(), a.begin(), a.end())); EXPECT_TRUE(std::equal(v.cbegin(), v.cend(), a.begin(), a.end())); EXPECT_TRUE(std::equal(v.rbegin(), v.rend(), ra.begin(), ra.end())); EXPECT_TRUE(std::equal(v.crbegin(), v.crend(), ra.begin(), ra.end())); } } template< typename Container, typename ValueType = typename Container::value_type> using lvalue_push_front_t = decltype( std::declval().push_front(std::declval())); template< typename Container, typename ValueType = typename Container::value_type> using rvalue_push_front_t = decltype(std::declval().push_front(0)); template using pop_front_t = decltype(std::declval().pop_front()); static_assert(ill_formed::value, ""); static_assert(ill_formed::value, ""); static_assert(ill_formed::value, ""); using std_deq_int = std::deque; static_assert(!ill_formed::value, ""); static_assert(!ill_formed::value, ""); static_assert(!ill_formed::value, ""); template< typename Container, typename ValueType = typename Container::value_type> using lvalue_push_back_t = decltype( std::declval().push_back(std::declval())); template< typename Container, typename ValueType = typename Container::value_type> using rvalue_push_back_t = decltype(std::declval().push_back(0)); template using pop_back_t = decltype(std::declval().pop_back()); static_assert(ill_formed::value, ""); static_assert(ill_formed::value, ""); static_assert(ill_formed::value, ""); using std_vec_int = std::vector; static_assert(!ill_formed::value, ""); static_assert(!ill_formed::value, ""); static_assert(!ill_formed::value, ""); TEST(array, front_back) { { arr_type v; v[0] = 0; v[1] = 0; v[2] = 0; v[3] = 0; v[4] = 0; static_assert(std::is_same::value, ""); static_assert(std::is_same::value, ""); v.front() = 9; v.back() = 8; EXPECT_EQ(v[0], v.front()); EXPECT_EQ(v[4], v.back()); } { arr_type v0; v0[0] = 3; v0[1] = 0; v0[2] = 2; v0[3] = 0; v0[4] = 1; arr_type const v = v0; EXPECT_EQ(v.front(), 3); EXPECT_EQ(v.back(), 1); static_assert( std::is_same::value, ""); static_assert(std::is_same::value, ""); } } TEST(array, index_at) { arr_type v0; v0[0] = 3; v0[1] = 2; v0[2] = 1; v0[3] = 0; v0[4] = 0; { arr_type v = v0; EXPECT_EQ(v[0], 3); EXPECT_EQ(v[1], 2); EXPECT_EQ(v[2], 1); EXPECT_NO_THROW(v.at(0)); EXPECT_NO_THROW(v.at(1)); EXPECT_NO_THROW(v.at(2)); EXPECT_THROW(v.at(5), std::out_of_range); static_assert(std::is_same::value, ""); static_assert(std::is_same::value, ""); v[0] = 8; v.at(1) = 9; EXPECT_EQ(v[0], 8); EXPECT_EQ(v[1], 9); } { arr_type const v = v0; EXPECT_EQ(v[0], 3); EXPECT_EQ(v[1], 2); EXPECT_EQ(v[2], 1); EXPECT_NO_THROW(v.at(0)); EXPECT_NO_THROW(v.at(1)); EXPECT_NO_THROW(v.at(2)); EXPECT_THROW(v.at(5), std::out_of_range); static_assert(std::is_same::value, ""); static_assert(std::is_same::value, ""); } } template using resize_t = decltype(std::declval().resize(0)); static_assert(ill_formed::value, ""); static_assert(!ill_formed::value, ""); template< typename Container, typename ValueType = typename Container::value_type> using lvalue_insert_t = decltype(std::declval().insert( std::declval().begin(), std::declval())); template< typename Container, typename ValueType = typename Container::value_type> using rvalue_insert_t = decltype(std::declval().insert( std::declval().begin(), std::declval())); template< typename Container, typename ValueType = typename Container::value_type> using insert_n_t = decltype(std::declval().insert( std::declval().begin(), 2, std::declval())); template< typename Container, typename ValueType = typename Container::value_type> using insert_il_t = decltype(std::declval().insert( std::declval().begin(), std::initializer_list{})); static_assert(ill_formed::value, ""); static_assert(ill_formed::value, ""); // TODO: Broken. Adding the proper constraint ICE's GCC 8, or infinitely // recurses within the compiler for GCC and Clang, depending on the constraint // technique used. #if 0 static_assert(ill_formed::value, ""); #endif static_assert(ill_formed::value, ""); static_assert(!ill_formed::value, ""); static_assert(!ill_formed::value, ""); static_assert(!ill_formed::value, ""); static_assert(!ill_formed::value, ""); template using erase_t = decltype( std::declval().erase(std::declval().begin())); static_assert(ill_formed::value, ""); static_assert(!ill_formed::value, ""); template using assign_t = decltype(std::declval().assign( std::declval(), std::declval())); template using assign_n_t = decltype(std::declval().assign(5, 5)); template using assign_il_t = decltype(std::declval().assign(std::initializer_list{})); template using assignment_operator_il_t = decltype(std::declval() = std::initializer_list{}); static_assert(ill_formed::value, ""); static_assert(ill_formed::value, ""); static_assert(ill_formed::value, ""); static_assert(ill_formed::value, ""); static_assert(!ill_formed::value, ""); static_assert(!ill_formed::value, ""); static_assert(!ill_formed::value, ""); static_assert(!ill_formed::value, ""); template using clear_t = decltype(std::declval().clear()); static_assert(ill_formed::value, ""); static_assert(!ill_formed::value, "");