From c2e754829628d1e9b7a16b3389cfdace76950fdf Mon Sep 17 00:00:00 2001 From: misterg Date: Tue, 19 Sep 2017 16:54:40 -0400 Subject: Initial Commit --- absl/types/span_test.cc | 783 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 783 insertions(+) create mode 100644 absl/types/span_test.cc (limited to 'absl/types/span_test.cc') diff --git a/absl/types/span_test.cc b/absl/types/span_test.cc new file mode 100644 index 00000000..22ea33e0 --- /dev/null +++ b/absl/types/span_test.cc @@ -0,0 +1,783 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/types/span.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/base/config.h" +#include "absl/base/internal/exception_testing.h" +#include "absl/base/macros.h" +#include "absl/base/port.h" +#include "absl/container/fixed_array.h" +#include "absl/container/inlined_vector.h" +#include "absl/strings/str_cat.h" + +namespace { + +MATCHER_P(DataIs, data, + absl::StrCat("data() is ", negation ? "is " : "isn't ", + testing::PrintToString(data))) { + return arg.data() == data; +} + +template +auto SpanIs(T data, size_t size) + -> decltype(testing::AllOf(DataIs(data), testing::SizeIs(size))) { + return testing::AllOf(DataIs(data), testing::SizeIs(size)); +} + +template +auto SpanIs(const Container& c) -> decltype(SpanIs(c.data(), c.size())) { + return SpanIs(c.data(), c.size()); +} + +std::vector MakeRamp(int len, int offset = 0) { + std::vector v(len); + std::iota(v.begin(), v.end(), offset); + return v; +} + +TEST(IntSpan, EmptyCtors) { + absl::Span s; + EXPECT_THAT(s, SpanIs(nullptr, 0)); +} + +TEST(IntSpan, PtrLenCtor) { + int a[] = {1, 2, 3}; + absl::Span s(&a[0], 2); + EXPECT_THAT(s, SpanIs(a, 2)); +} + +TEST(IntSpan, ArrayCtor) { + int a[] = {1, 2, 3}; + absl::Span s(a); + EXPECT_THAT(s, SpanIs(a, 3)); + + EXPECT_TRUE((std::is_constructible, int[3]>::value)); + EXPECT_TRUE( + (std::is_constructible, const int[3]>::value)); + EXPECT_FALSE((std::is_constructible, const int[3]>::value)); + EXPECT_TRUE((std::is_convertible>::value)); + EXPECT_TRUE( + (std::is_convertible>::value)); +} + +template +void TakesGenericSpan(absl::Span) {} + +TEST(IntSpan, ContainerCtor) { + std::vector empty; + absl::Span s_empty(empty); + EXPECT_THAT(s_empty, SpanIs(empty)); + + std::vector filled{1, 2, 3}; + absl::Span s_filled(filled); + EXPECT_THAT(s_filled, SpanIs(filled)); + + absl::Span s_from_span(filled); + EXPECT_THAT(s_from_span, SpanIs(s_filled)); + + absl::Span const_filled = filled; + EXPECT_THAT(const_filled, SpanIs(filled)); + + absl::Span const_from_span = s_filled; + EXPECT_THAT(const_from_span, SpanIs(s_filled)); + + EXPECT_TRUE( + (std::is_convertible&, absl::Span>::value)); + EXPECT_TRUE( + (std::is_convertible&, absl::Span>::value)); + + TakesGenericSpan(absl::Span(filled)); +} + +// A struct supplying shallow data() const. +struct ContainerWithShallowConstData { + std::vector storage; + int* data() const { return const_cast(storage.data()); } + int size() const { return storage.size(); } +}; + +TEST(IntSpan, ShallowConstness) { + const ContainerWithShallowConstData c{MakeRamp(20)}; + absl::Span s( + c); // We should be able to do this even though data() is const. + s[0] = -1; + EXPECT_EQ(c.storage[0], -1); +} + +TEST(CharSpan, StringCtor) { + std::string empty = ""; + absl::Span s_empty(empty); + EXPECT_THAT(s_empty, SpanIs(empty)); + + std::string abc = "abc"; + absl::Span s_abc(abc); + EXPECT_THAT(s_abc, SpanIs(abc)); + + absl::Span s_const_abc = abc; + EXPECT_THAT(s_const_abc, SpanIs(abc)); + + EXPECT_FALSE((std::is_constructible, std::string>::value)); + EXPECT_FALSE((std::is_constructible, std::string>::value)); + EXPECT_TRUE((std::is_convertible>::value)); +} + +TEST(IntSpan, FromConstPointer) { + EXPECT_TRUE((std::is_constructible, + std::vector>::value)); + EXPECT_TRUE((std::is_constructible, + std::vector>::value)); + EXPECT_FALSE(( + std::is_constructible, std::vector>::value)); + EXPECT_FALSE(( + std::is_constructible, std::vector>::value)); +} + +struct TypeWithMisleadingData { + int& data() { return i; } + int size() { return 1; } + int i; +}; + +struct TypeWithMisleadingSize { + int* data() { return &i; } + const char* size() { return "1"; } + int i; +}; + +TEST(IntSpan, EvilTypes) { + EXPECT_FALSE( + (std::is_constructible, TypeWithMisleadingData&>::value)); + EXPECT_FALSE( + (std::is_constructible, TypeWithMisleadingSize&>::value)); +} + +struct Base { + int* data() { return &i; } + int size() { return 1; } + int i; +}; +struct Derived : Base {}; + +TEST(IntSpan, SpanOfDerived) { + EXPECT_TRUE((std::is_constructible, Base&>::value)); + EXPECT_TRUE((std::is_constructible, Derived&>::value)); + EXPECT_FALSE( + (std::is_constructible, std::vector>::value)); +} + +void TestInitializerList(absl::Span s, const std::vector& v) { + EXPECT_TRUE(absl::equal(s.begin(), s.end(), v.begin(), v.end())); +} + +TEST(ConstIntSpan, InitializerListConversion) { + TestInitializerList({}, {}); + TestInitializerList({1}, {1}); + TestInitializerList({1, 2, 3}, {1, 2, 3}); + + EXPECT_FALSE((std::is_constructible, + std::initializer_list>::value)); + EXPECT_FALSE(( + std::is_convertible, std::initializer_list>::value)); +} + +TEST(IntSpan, Data) { + int i; + absl::Span s(&i, 1); + EXPECT_EQ(&i, s.data()); +} + +TEST(IntSpan, SizeLengthEmpty) { + absl::Span empty; + EXPECT_EQ(empty.size(), 0); + EXPECT_TRUE(empty.empty()); + EXPECT_EQ(empty.size(), empty.length()); + + auto v = MakeRamp(10); + absl::Span s(v); + EXPECT_EQ(s.size(), 10); + EXPECT_FALSE(s.empty()); + EXPECT_EQ(s.size(), s.length()); +} + +TEST(IntSpan, ElementAccess) { + auto v = MakeRamp(10); + absl::Span s(v); + for (int i = 0; i < s.size(); ++i) { + EXPECT_EQ(s[i], s.at(i)); + } + + EXPECT_EQ(s.front(), s[0]); + EXPECT_EQ(s.back(), s[9]); +} + +TEST(IntSpan, AtThrows) { + auto v = MakeRamp(10); + absl::Span s(v); + + EXPECT_EQ(s.at(9), 9); + ABSL_BASE_INTERNAL_EXPECT_FAIL(s.at(10), std::out_of_range, + "failed bounds check"); +} + +TEST(IntSpan, RemovePrefixAndSuffix) { + auto v = MakeRamp(20, 1); + absl::Span s(v); + EXPECT_EQ(s.size(), 20); + + s.remove_suffix(0); + s.remove_prefix(0); + EXPECT_EQ(s.size(), 20); + + s.remove_prefix(1); + EXPECT_EQ(s.size(), 19); + EXPECT_EQ(s[0], 2); + + s.remove_suffix(1); + EXPECT_EQ(s.size(), 18); + EXPECT_EQ(s.back(), 19); + + s.remove_prefix(7); + EXPECT_EQ(s.size(), 11); + EXPECT_EQ(s[0], 9); + + s.remove_suffix(11); + EXPECT_EQ(s.size(), 0); + + EXPECT_EQ(v, MakeRamp(20, 1)); +} + +TEST(IntSpan, Subspan) { + std::vector empty; + EXPECT_EQ(absl::MakeSpan(empty).subspan(), empty); + EXPECT_THAT(absl::MakeSpan(empty).subspan(0, 0), SpanIs(empty)); + EXPECT_THAT(absl::MakeSpan(empty).subspan(0, absl::Span::npos), + SpanIs(empty)); + + auto ramp = MakeRamp(10); + EXPECT_THAT(absl::MakeSpan(ramp).subspan(), SpanIs(ramp)); + EXPECT_THAT(absl::MakeSpan(ramp).subspan(0, 10), SpanIs(ramp)); + EXPECT_THAT(absl::MakeSpan(ramp).subspan(0, absl::Span::npos), + SpanIs(ramp)); + EXPECT_THAT(absl::MakeSpan(ramp).subspan(0, 3), SpanIs(ramp.data(), 3)); + EXPECT_THAT(absl::MakeSpan(ramp).subspan(5, absl::Span::npos), + SpanIs(ramp.data() + 5, 5)); + EXPECT_THAT(absl::MakeSpan(ramp).subspan(3, 3), SpanIs(ramp.data() + 3, 3)); + EXPECT_THAT(absl::MakeSpan(ramp).subspan(10, 5), SpanIs(ramp.data() + 10, 0)); + +#ifdef ABSL_HAVE_EXCEPTIONS + EXPECT_THROW(absl::MakeSpan(ramp).subspan(11, 5), std::out_of_range); +#else + EXPECT_DEATH(absl::MakeSpan(ramp).subspan(11, 5), ""); +#endif +} + +TEST(IntSpan, MakeSpanPtrLength) { + std::vector empty; + auto s_empty = absl::MakeSpan(empty.data(), empty.size()); + EXPECT_THAT(s_empty, SpanIs(empty)); + + std::array a{{1, 2, 3}}; + auto s = absl::MakeSpan(a.data(), a.size()); + EXPECT_THAT(s, SpanIs(a)); + + EXPECT_THAT(absl::MakeConstSpan(empty.data(), empty.size()), SpanIs(s_empty)); + EXPECT_THAT(absl::MakeConstSpan(a.data(), a.size()), SpanIs(s)); +} + +TEST(IntSpan, MakeSpanTwoPtrs) { + std::vector empty; + auto s_empty = absl::MakeSpan(empty.data(), empty.data()); + EXPECT_THAT(s_empty, SpanIs(empty)); + + std::vector v{1, 2, 3}; + auto s = absl::MakeSpan(v.data(), v.data() + 1); + EXPECT_THAT(s, SpanIs(v.data(), 1)); + + EXPECT_THAT(absl::MakeConstSpan(empty.data(), empty.data()), SpanIs(s_empty)); + EXPECT_THAT(absl::MakeConstSpan(v.data(), v.data() + 1), SpanIs(s)); +} + +TEST(IntSpan, MakeSpanContainer) { + std::vector empty; + auto s_empty = absl::MakeSpan(empty); + EXPECT_THAT(s_empty, SpanIs(empty)); + + std::vector v{1, 2, 3}; + auto s = absl::MakeSpan(v); + EXPECT_THAT(s, SpanIs(v)); + + EXPECT_THAT(absl::MakeConstSpan(empty), SpanIs(s_empty)); + EXPECT_THAT(absl::MakeConstSpan(v), SpanIs(s)); + + EXPECT_THAT(absl::MakeSpan(s), SpanIs(s)); + EXPECT_THAT(absl::MakeConstSpan(s), SpanIs(s)); +} + +TEST(CharSpan, MakeSpanString) { + std::string empty = ""; + auto s_empty = absl::MakeSpan(empty); + EXPECT_THAT(s_empty, SpanIs(empty)); + + std::string str = "abc"; + auto s_str = absl::MakeSpan(str); + EXPECT_THAT(s_str, SpanIs(str)); + + EXPECT_THAT(absl::MakeConstSpan(empty), SpanIs(s_empty)); + EXPECT_THAT(absl::MakeConstSpan(str), SpanIs(s_str)); +} + +TEST(IntSpan, MakeSpanArray) { + int a[] = {1, 2, 3}; + auto s = absl::MakeSpan(a); + EXPECT_THAT(s, SpanIs(a, 3)); + + const int ca[] = {1, 2, 3}; + auto s_ca = absl::MakeSpan(ca); + EXPECT_THAT(s_ca, SpanIs(ca, 3)); + + EXPECT_THAT(absl::MakeConstSpan(a), SpanIs(s)); + EXPECT_THAT(absl::MakeConstSpan(ca), SpanIs(s_ca)); +} + +// Compile-asserts that the argument has the expected decayed type. +template +void CheckType(const T& /* value */) { + testing::StaticAssertTypeEq(); +} + +TEST(IntSpan, MakeSpanTypes) { + std::vector vec; + const std::vector cvec; + int a[1]; + const int ca[] = {1}; + int* ip = a; + const int* cip = ca; + std::string s = ""; + const std::string cs = ""; + CheckType>(absl::MakeSpan(vec)); + CheckType>(absl::MakeSpan(cvec)); + CheckType>(absl::MakeSpan(ip, ip + 1)); + CheckType>(absl::MakeSpan(ip, 1)); + CheckType>(absl::MakeSpan(cip, cip + 1)); + CheckType>(absl::MakeSpan(cip, 1)); + CheckType>(absl::MakeSpan(a)); + CheckType>(absl::MakeSpan(a, a + 1)); + CheckType>(absl::MakeSpan(a, 1)); + CheckType>(absl::MakeSpan(ca)); + CheckType>(absl::MakeSpan(ca, ca + 1)); + CheckType>(absl::MakeSpan(ca, 1)); + CheckType>(absl::MakeSpan(s)); + CheckType>(absl::MakeSpan(cs)); +} + +TEST(ConstIntSpan, MakeConstSpanTypes) { + std::vector vec; + const std::vector cvec; + int array[1]; + const int carray[] = {0}; + int* ptr = array; + const int* cptr = carray; + std::string s = ""; + std::string cs = ""; + CheckType>(absl::MakeConstSpan(vec)); + CheckType>(absl::MakeConstSpan(cvec)); + CheckType>(absl::MakeConstSpan(ptr, ptr + 1)); + CheckType>(absl::MakeConstSpan(ptr, 1)); + CheckType>(absl::MakeConstSpan(cptr, cptr + 1)); + CheckType>(absl::MakeConstSpan(cptr, 1)); + CheckType>(absl::MakeConstSpan(array)); + CheckType>(absl::MakeConstSpan(carray)); + CheckType>(absl::MakeConstSpan(s)); + CheckType>(absl::MakeConstSpan(cs)); +} + +TEST(IntSpan, Equality) { + const int arr1[] = {1, 2, 3, 4, 5}; + int arr2[] = {1, 2, 3, 4, 5}; + std::vector vec1(std::begin(arr1), std::end(arr1)); + std::vector vec2 = vec1; + std::vector other_vec = {2, 4, 6, 8, 10}; + // These two slices are from different vectors, but have the same size and + // have the same elements (right now). They should compare equal. Test both + // == and !=. + const absl::Span from1 = vec1; + const absl::Span from2 = vec2; + EXPECT_EQ(from1, from1); + EXPECT_FALSE(from1 != from1); + EXPECT_EQ(from1, from2); + EXPECT_FALSE(from1 != from2); + + // These two slices have different underlying vector values. They should be + // considered not equal. Test both == and !=. + const absl::Span from_other = other_vec; + EXPECT_NE(from1, from_other); + EXPECT_FALSE(from1 == from_other); + + // Comparison between a vector and its slice should be equal. And vice-versa. + // This ensures implicit conversion to Span works on both sides of ==. + EXPECT_EQ(vec1, from1); + EXPECT_FALSE(vec1 != from1); + EXPECT_EQ(from1, vec1); + EXPECT_FALSE(from1 != vec1); + + // This verifies that absl::Span can be compared freely with + // absl::Span. + const absl::Span mutable_from1(vec1); + const absl::Span mutable_from2(vec2); + EXPECT_EQ(from1, mutable_from1); + EXPECT_EQ(mutable_from1, from1); + EXPECT_EQ(mutable_from1, mutable_from2); + EXPECT_EQ(mutable_from2, mutable_from1); + + // Comparison between a vector and its slice should be equal for mutable + // Spans as well. + EXPECT_EQ(vec1, mutable_from1); + EXPECT_FALSE(vec1 != mutable_from1); + EXPECT_EQ(mutable_from1, vec1); + EXPECT_FALSE(mutable_from1 != vec1); + + // Comparison between convertible-to-Span-of-const and Span-of-mutable. Arrays + // are used because they're the only value type which converts to a + // Span-of-mutable. EXPECT_TRUE is used instead of EXPECT_EQ to avoid + // array-to-pointer decay. + EXPECT_TRUE(arr1 == mutable_from1); + EXPECT_FALSE(arr1 != mutable_from1); + EXPECT_TRUE(mutable_from1 == arr1); + EXPECT_FALSE(mutable_from1 != arr1); + + // Comparison between convertible-to-Span-of-mutable and Span-of-const + EXPECT_TRUE(arr2 == from1); + EXPECT_FALSE(arr2 != from1); + EXPECT_TRUE(from1 == arr2); + EXPECT_FALSE(from1 != arr2); + + // With a different size, the array slices should not be equal. + EXPECT_NE(from1, absl::Span(from1).subspan(0, from1.size() - 1)); + + // With different contents, the array slices should not be equal. + ++vec2.back(); + EXPECT_NE(from1, from2); +} + +class IntSpanOrderComparisonTest : public testing::Test { + public: + IntSpanOrderComparisonTest() + : arr_before_{1, 2, 3}, + arr_after_{1, 2, 4}, + carr_after_{1, 2, 4}, + vec_before_(std::begin(arr_before_), std::end(arr_before_)), + vec_after_(std::begin(arr_after_), std::end(arr_after_)), + before_(vec_before_), + after_(vec_after_), + cbefore_(vec_before_), + cafter_(vec_after_) {} + + protected: + int arr_before_[3], arr_after_[3]; + const int carr_after_[3]; + std::vector vec_before_, vec_after_; + absl::Span before_, after_; + absl::Span cbefore_, cafter_; +}; + +TEST_F(IntSpanOrderComparisonTest, CompareSpans) { + EXPECT_TRUE(cbefore_ < cafter_); + EXPECT_TRUE(cbefore_ <= cafter_); + EXPECT_TRUE(cafter_ > cbefore_); + EXPECT_TRUE(cafter_ >= cbefore_); + + EXPECT_FALSE(cbefore_ > cafter_); + EXPECT_FALSE(cafter_ < cbefore_); + + EXPECT_TRUE(before_ < after_); + EXPECT_TRUE(before_ <= after_); + EXPECT_TRUE(after_ > before_); + EXPECT_TRUE(after_ >= before_); + + EXPECT_FALSE(before_ > after_); + EXPECT_FALSE(after_ < before_); + + EXPECT_TRUE(cbefore_ < after_); + EXPECT_TRUE(cbefore_ <= after_); + EXPECT_TRUE(after_ > cbefore_); + EXPECT_TRUE(after_ >= cbefore_); + + EXPECT_FALSE(cbefore_ > after_); + EXPECT_FALSE(after_ < cbefore_); +} + +TEST_F(IntSpanOrderComparisonTest, SpanOfConstAndContainer) { + EXPECT_TRUE(cbefore_ < vec_after_); + EXPECT_TRUE(cbefore_ <= vec_after_); + EXPECT_TRUE(vec_after_ > cbefore_); + EXPECT_TRUE(vec_after_ >= cbefore_); + + EXPECT_FALSE(cbefore_ > vec_after_); + EXPECT_FALSE(vec_after_ < cbefore_); + + EXPECT_TRUE(arr_before_ < cafter_); + EXPECT_TRUE(arr_before_ <= cafter_); + EXPECT_TRUE(cafter_ > arr_before_); + EXPECT_TRUE(cafter_ >= arr_before_); + + EXPECT_FALSE(arr_before_ > cafter_); + EXPECT_FALSE(cafter_ < arr_before_); +} + +TEST_F(IntSpanOrderComparisonTest, SpanOfMutableAndContainer) { + EXPECT_TRUE(vec_before_ < after_); + EXPECT_TRUE(vec_before_ <= after_); + EXPECT_TRUE(after_ > vec_before_); + EXPECT_TRUE(after_ >= vec_before_); + + EXPECT_FALSE(vec_before_ > after_); + EXPECT_FALSE(after_ < vec_before_); + + EXPECT_TRUE(before_ < carr_after_); + EXPECT_TRUE(before_ <= carr_after_); + EXPECT_TRUE(carr_after_ > before_); + EXPECT_TRUE(carr_after_ >= before_); + + EXPECT_FALSE(before_ > carr_after_); + EXPECT_FALSE(carr_after_ < before_); +} + +TEST_F(IntSpanOrderComparisonTest, EqualSpans) { + EXPECT_FALSE(before_ < before_); + EXPECT_TRUE(before_ <= before_); + EXPECT_FALSE(before_ > before_); + EXPECT_TRUE(before_ >= before_); +} + +TEST_F(IntSpanOrderComparisonTest, Subspans) { + auto subspan = before_.subspan(0, 1); + EXPECT_TRUE(subspan < before_); + EXPECT_TRUE(subspan <= before_); + EXPECT_TRUE(before_ > subspan); + EXPECT_TRUE(before_ >= subspan); + + EXPECT_FALSE(subspan > before_); + EXPECT_FALSE(before_ < subspan); +} + +TEST_F(IntSpanOrderComparisonTest, EmptySpans) { + absl::Span empty; + EXPECT_FALSE(empty < empty); + EXPECT_TRUE(empty <= empty); + EXPECT_FALSE(empty > empty); + EXPECT_TRUE(empty >= empty); + + EXPECT_TRUE(empty < before_); + EXPECT_TRUE(empty <= before_); + EXPECT_TRUE(before_ > empty); + EXPECT_TRUE(before_ >= empty); + + EXPECT_FALSE(empty > before_); + EXPECT_FALSE(before_ < empty); +} + +TEST(IntSpan, ExposesContainerTypesAndConsts) { + absl::Span slice; + CheckType::iterator>(slice.begin()); + EXPECT_TRUE((std::is_convertible::const_iterator>::value)); + CheckType::const_iterator>(slice.cbegin()); + EXPECT_TRUE((std::is_convertible::const_iterator>::value)); + CheckType::const_iterator>(slice.cend()); + CheckType::reverse_iterator>(slice.rend()); + EXPECT_TRUE( + (std::is_convertible::const_reverse_iterator>::value)); + CheckType::const_reverse_iterator>(slice.crend()); + testing::StaticAssertTypeEq::value_type>(); + testing::StaticAssertTypeEq::value_type>(); + testing::StaticAssertTypeEq::pointer>(); + testing::StaticAssertTypeEq::pointer>(); + testing::StaticAssertTypeEq::reference>(); + testing::StaticAssertTypeEq::reference>(); + testing::StaticAssertTypeEq::const_reference>(); + testing::StaticAssertTypeEq::const_reference>(); + EXPECT_EQ(static_cast::size_type>(-1), absl::Span::npos); +} + +TEST(IntSpan, IteratorsAndReferences) { + auto accept_pointer = [](int*) {}; + auto accept_reference = [](int&) {}; + auto accept_iterator = [](absl::Span::iterator) {}; + auto accept_const_iterator = [](absl::Span::const_iterator) {}; + auto accept_reverse_iterator = [](absl::Span::reverse_iterator) {}; + auto accept_const_reverse_iterator = + [](absl::Span::const_reverse_iterator) {}; + + int a[1]; + absl::Span s = a; + + accept_pointer(s.data()); + accept_iterator(s.begin()); + accept_const_iterator(s.begin()); + accept_const_iterator(s.cbegin()); + accept_iterator(s.end()); + accept_const_iterator(s.end()); + accept_const_iterator(s.cend()); + accept_reverse_iterator(s.rbegin()); + accept_const_reverse_iterator(s.rbegin()); + accept_const_reverse_iterator(s.crbegin()); + accept_reverse_iterator(s.rend()); + accept_const_reverse_iterator(s.rend()); + accept_const_reverse_iterator(s.crend()); + + accept_reference(s[0]); + accept_reference(s.at(0)); + accept_reference(s.front()); + accept_reference(s.back()); +} + +TEST(IntSpan, IteratorsAndReferences_Const) { + auto accept_pointer = [](int*) {}; + auto accept_reference = [](int&) {}; + auto accept_iterator = [](absl::Span::iterator) {}; + auto accept_const_iterator = [](absl::Span::const_iterator) {}; + auto accept_reverse_iterator = [](absl::Span::reverse_iterator) {}; + auto accept_const_reverse_iterator = + [](absl::Span::const_reverse_iterator) {}; + + int a[1]; + const absl::Span s = a; + + accept_pointer(s.data()); + accept_iterator(s.begin()); + accept_const_iterator(s.begin()); + accept_const_iterator(s.cbegin()); + accept_iterator(s.end()); + accept_const_iterator(s.end()); + accept_const_iterator(s.cend()); + accept_reverse_iterator(s.rbegin()); + accept_const_reverse_iterator(s.rbegin()); + accept_const_reverse_iterator(s.crbegin()); + accept_reverse_iterator(s.rend()); + accept_const_reverse_iterator(s.rend()); + accept_const_reverse_iterator(s.crend()); + + accept_reference(s[0]); + accept_reference(s.at(0)); + accept_reference(s.front()); + accept_reference(s.back()); +} + +TEST(IntSpan, NoexceptTest) { + int a[] = {1, 2, 3}; + std::vector v; + EXPECT_TRUE(noexcept(absl::Span())); + EXPECT_TRUE(noexcept(absl::Span(a, 2))); + EXPECT_TRUE(noexcept(absl::Span(a))); + EXPECT_TRUE(noexcept(absl::Span(v))); + EXPECT_TRUE(noexcept(absl::Span(v))); + EXPECT_TRUE(noexcept(absl::Span({1, 2, 3}))); + EXPECT_TRUE(noexcept(absl::MakeSpan(v))); + EXPECT_TRUE(noexcept(absl::MakeSpan(a))); + EXPECT_TRUE(noexcept(absl::MakeSpan(a, 2))); + EXPECT_TRUE(noexcept(absl::MakeSpan(a, a + 1))); + EXPECT_TRUE(noexcept(absl::MakeConstSpan(v))); + EXPECT_TRUE(noexcept(absl::MakeConstSpan(a))); + EXPECT_TRUE(noexcept(absl::MakeConstSpan(a, 2))); + EXPECT_TRUE(noexcept(absl::MakeConstSpan(a, a + 1))); + + absl::Span s(v); + EXPECT_TRUE(noexcept(s.data())); + EXPECT_TRUE(noexcept(s.size())); + EXPECT_TRUE(noexcept(s.length())); + EXPECT_TRUE(noexcept(s.empty())); + EXPECT_TRUE(noexcept(s[0])); + EXPECT_TRUE(noexcept(s.front())); + EXPECT_TRUE(noexcept(s.back())); + EXPECT_TRUE(noexcept(s.begin())); + EXPECT_TRUE(noexcept(s.cbegin())); + EXPECT_TRUE(noexcept(s.end())); + EXPECT_TRUE(noexcept(s.cend())); + EXPECT_TRUE(noexcept(s.rbegin())); + EXPECT_TRUE(noexcept(s.crbegin())); + EXPECT_TRUE(noexcept(s.rend())); + EXPECT_TRUE(noexcept(s.crend())); + EXPECT_TRUE(noexcept(s.remove_prefix(0))); + EXPECT_TRUE(noexcept(s.remove_suffix(0))); +} + +// ConstexprTester exercises expressions in a constexpr context. Simply placing +// the expression in a constexpr function is not enough, as some compilers will +// simply compile the constexpr function as runtime code. Using template +// parameters forces compile-time execution. +template +struct ConstexprTester {}; + +#define ABSL_TEST_CONSTEXPR(expr) \ + do { \ + ABSL_ATTRIBUTE_UNUSED ConstexprTester<(expr, 1)> t; \ + } while (0) + +struct ContainerWithConstexprMethods { + constexpr int size() const { return 1; } + constexpr const int* data() const { return &i; } + const int i; +}; + +TEST(ConstIntSpan, ConstexprTest) { + static constexpr int a[] = {1, 2, 3}; + static constexpr int sized_arr[2] = {1, 2}; + static constexpr ContainerWithConstexprMethods c{1}; + ABSL_TEST_CONSTEXPR(absl::Span()); + ABSL_TEST_CONSTEXPR(absl::Span(a, 2)); + ABSL_TEST_CONSTEXPR(absl::Span(sized_arr)); + ABSL_TEST_CONSTEXPR(absl::Span(c)); + ABSL_TEST_CONSTEXPR(absl::MakeSpan(&a[0], 1)); + ABSL_TEST_CONSTEXPR(absl::MakeSpan(c)); + ABSL_TEST_CONSTEXPR(absl::MakeSpan(a)); + ABSL_TEST_CONSTEXPR(absl::MakeConstSpan(&a[0], 1)); + ABSL_TEST_CONSTEXPR(absl::MakeConstSpan(c)); + ABSL_TEST_CONSTEXPR(absl::MakeConstSpan(a)); + + constexpr absl::Span span = c; + ABSL_TEST_CONSTEXPR(span.data()); + ABSL_TEST_CONSTEXPR(span.size()); + ABSL_TEST_CONSTEXPR(span.length()); + ABSL_TEST_CONSTEXPR(span.empty()); + ABSL_TEST_CONSTEXPR(span.begin()); + ABSL_TEST_CONSTEXPR(span.cbegin()); + ABSL_TEST_CONSTEXPR(span.subspan(0, 0)); + ABSL_TEST_CONSTEXPR(span[0]); +} + +struct BigStruct { + char bytes[10000]; +}; + +TEST(Span, SpanSize) { + EXPECT_LE(sizeof(absl::Span), 2 * sizeof(void*)); + EXPECT_LE(sizeof(absl::Span), 2 * sizeof(void*)); +} + +} // namespace -- cgit v1.2.3