fune/mfbt/tests/gtest/TestSpan.cpp
Stanca Serban cefd926755 Backed out 9 changesets (bug 1826760, bug 1826758, bug 1826752, bug 1826756, bug 1826759, bug 1826761, bug 1826757, bug 1826753, bug 1826754) for causing bp-hybrid bustages in ClearKeyDecryptionManager.cpp.
CLOSED TREE

Backed out changeset 210012222277 (bug 1826761)
Backed out changeset e364bb149efa (bug 1826760)
Backed out changeset e456e2f9966c (bug 1826759)
Backed out changeset 2b6ff545f4a3 (bug 1826758)
Backed out changeset 95fe1de8ba00 (bug 1826757)
Backed out changeset f8af52d7f2a1 (bug 1826756)
Backed out changeset 2646e773f098 (bug 1826754)
Backed out changeset 58d5d74b1835 (bug 1826753)
Backed out changeset 8567e6595acc (bug 1826752)
2023-04-17 13:52:39 +03:00

2354 lines
56 KiB
C++

///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
///////////////////////////////////////////////////////////////////////////////
// Adapted from
// https://github.com/Microsoft/GSL/blob/3819df6e378ffccf0e29465afe99c3b324c2aa70/tests/Span_tests.cpp
#include "gtest/gtest.h"
#include "mozilla/Span.h"
#include "nsString.h"
#include "nsTArray.h"
#include "mozilla/Range.h"
#include <type_traits>
#define SPAN_TEST(name) TEST(SpanTest, name)
#define CHECK_THROW(a, b)
using namespace mozilla;
static_assert(std::is_convertible_v<Range<int>, Span<const int>>,
"Range should convert into const");
static_assert(std::is_convertible_v<Range<const int>, Span<const int>>,
"const Range should convert into const");
static_assert(!std::is_convertible_v<Range<const int>, Span<int>>,
"Range should not drop const in conversion");
static_assert(std::is_convertible_v<Span<int>, Range<const int>>,
"Span should convert into const");
static_assert(std::is_convertible_v<Span<const int>, Range<const int>>,
"const Span should convert into const");
static_assert(!std::is_convertible_v<Span<const int>, Range<int>>,
"Span should not drop const in conversion");
static_assert(std::is_convertible_v<Span<const int>, Span<const int>>,
"const Span should convert into const");
static_assert(std::is_convertible_v<Span<int>, Span<const int>>,
"Span should convert into const");
static_assert(!std::is_convertible_v<Span<const int>, Span<int>>,
"Span should not drop const in conversion");
static_assert(std::is_convertible_v<const nsTArray<int>, Span<const int>>,
"const nsTArray should convert into const");
static_assert(std::is_convertible_v<nsTArray<int>, Span<const int>>,
"nsTArray should convert into const");
static_assert(!std::is_convertible_v<const nsTArray<int>, Span<int>>,
"nsTArray should not drop const in conversion");
static_assert(std::is_convertible_v<nsTArray<const int>, Span<const int>>,
"nsTArray should convert into const");
static_assert(!std::is_convertible_v<nsTArray<const int>, Span<int>>,
"nsTArray should not drop const in conversion");
static_assert(std::is_convertible_v<const std::vector<int>, Span<const int>>,
"const std::vector should convert into const");
static_assert(std::is_convertible_v<std::vector<int>, Span<const int>>,
"std::vector should convert into const");
static_assert(!std::is_convertible_v<const std::vector<int>, Span<int>>,
"std::vector should not drop const in conversion");
/**
* Rust slice-compatible nullptr replacement value.
*/
#define SLICE_CONST_INT_PTR reinterpret_cast<const int*>(alignof(const int))
/**
* Rust slice-compatible nullptr replacement value.
*/
#define SLICE_INT_PTR reinterpret_cast<int*>(alignof(int))
/**
* Rust slice-compatible nullptr replacement value.
*/
#define SLICE_CONST_INT_PTR_PTR \
reinterpret_cast<const int**>(alignof(const int*))
/**
* Rust slice-compatible nullptr replacement value.
*/
#define SLICE_INT_PTR_PTR reinterpret_cast<int**>(alignof(int*))
namespace {
struct BaseClass {};
struct DerivedClass : BaseClass {};
} // namespace
void AssertSpanOfThreeInts(Span<const int> s) {
ASSERT_EQ(s.size(), 3U);
ASSERT_EQ(s[0], 1);
ASSERT_EQ(s[1], 2);
ASSERT_EQ(s[2], 3);
}
void AssertSpanOfThreeChars(Span<const char> s) {
ASSERT_EQ(s.size(), 3U);
ASSERT_EQ(s[0], 'a');
ASSERT_EQ(s[1], 'b');
ASSERT_EQ(s[2], 'c');
}
void AssertSpanOfThreeChar16s(Span<const char16_t> s) {
ASSERT_EQ(s.size(), 3U);
ASSERT_EQ(s[0], 'a');
ASSERT_EQ(s[1], 'b');
ASSERT_EQ(s[2], 'c');
}
void AssertSpanOfThreeCharsViaString(const nsACString& aStr) {
AssertSpanOfThreeChars(aStr);
}
void AssertSpanOfThreeChar16sViaString(const nsAString& aStr) {
AssertSpanOfThreeChar16s(aStr);
}
SPAN_TEST(default_constructor) {
{
Span<int> s;
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), SLICE_INT_PTR);
Span<const int> cs;
ASSERT_EQ(cs.Length(), 0U);
ASSERT_EQ(cs.data(), SLICE_CONST_INT_PTR);
}
{
Span<int, 0> s;
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), SLICE_INT_PTR);
Span<const int, 0> cs;
ASSERT_EQ(cs.Length(), 0U);
ASSERT_EQ(cs.data(), SLICE_CONST_INT_PTR);
}
{
#ifdef CONFIRM_COMPILATION_ERRORS
Span<int, 1> s;
ASSERT_EQ(s.Length(), 1U);
ASSERT_EQ(s.data(), SLICE_INT_PTR); // explains why it can't compile
#endif
}
{
Span<int> s{};
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), SLICE_INT_PTR);
Span<const int> cs{};
ASSERT_EQ(cs.Length(), 0U);
ASSERT_EQ(cs.data(), SLICE_CONST_INT_PTR);
}
}
SPAN_TEST(size_optimization) {
{
Span<int> s;
ASSERT_EQ(sizeof(s), sizeof(int*) + sizeof(size_t));
}
{
Span<int, 0> s;
ASSERT_EQ(sizeof(s), sizeof(int*));
}
}
SPAN_TEST(from_nullptr_constructor) {
{
Span<int> s = nullptr;
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), SLICE_INT_PTR);
Span<const int> cs = nullptr;
ASSERT_EQ(cs.Length(), 0U);
ASSERT_EQ(cs.data(), SLICE_CONST_INT_PTR);
}
{
Span<int, 0> s = nullptr;
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), SLICE_INT_PTR);
Span<const int, 0> cs = nullptr;
ASSERT_EQ(cs.Length(), 0U);
ASSERT_EQ(cs.data(), SLICE_CONST_INT_PTR);
}
{
#ifdef CONFIRM_COMPILATION_ERRORS
Span<int, 1> s = nullptr;
ASSERT_EQ(s.Length(), 1U);
ASSERT_EQ(s.data(), SLICE_INT_PTR); // explains why it can't compile
#endif
}
{
Span<int> s{nullptr};
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), SLICE_INT_PTR);
Span<const int> cs{nullptr};
ASSERT_EQ(cs.Length(), 0U);
ASSERT_EQ(cs.data(), SLICE_CONST_INT_PTR);
}
{
Span<int*> s{nullptr};
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), SLICE_INT_PTR_PTR);
Span<const int*> cs{nullptr};
ASSERT_EQ(cs.Length(), 0U);
ASSERT_EQ(cs.data(), SLICE_CONST_INT_PTR_PTR);
}
}
SPAN_TEST(from_nullptr_length_constructor) {
{
Span<int> s{nullptr, static_cast<Span<int>::index_type>(0)};
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), SLICE_INT_PTR);
Span<const int> cs{nullptr, static_cast<Span<int>::index_type>(0)};
ASSERT_EQ(cs.Length(), 0U);
ASSERT_EQ(cs.data(), SLICE_CONST_INT_PTR);
}
{
Span<int, 0> s{nullptr, static_cast<Span<int>::index_type>(0)};
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), SLICE_INT_PTR);
Span<const int, 0> cs{nullptr, static_cast<Span<int>::index_type>(0)};
ASSERT_EQ(cs.Length(), 0U);
ASSERT_EQ(cs.data(), SLICE_CONST_INT_PTR);
}
#if 0
{
auto workaround_macro = []() { Span<int, 1> s{ nullptr, static_cast<Span<int>::index_type>(0) }; };
CHECK_THROW(workaround_macro(), fail_fast);
}
{
auto workaround_macro = []() { Span<int> s{nullptr, 1}; };
CHECK_THROW(workaround_macro(), fail_fast);
auto const_workaround_macro = []() { Span<const int> cs{nullptr, 1}; };
CHECK_THROW(const_workaround_macro(), fail_fast);
}
{
auto workaround_macro = []() { Span<int, 0> s{nullptr, 1}; };
CHECK_THROW(workaround_macro(), fail_fast);
auto const_workaround_macro = []() { Span<const int, 0> s{nullptr, 1}; };
CHECK_THROW(const_workaround_macro(), fail_fast);
}
#endif
{
Span<int*> s{nullptr, static_cast<Span<int>::index_type>(0)};
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), SLICE_INT_PTR_PTR);
Span<const int*> cs{nullptr, static_cast<Span<int>::index_type>(0)};
ASSERT_EQ(cs.Length(), 0U);
ASSERT_EQ(cs.data(), SLICE_CONST_INT_PTR_PTR);
}
}
SPAN_TEST(from_pointer_length_constructor) {
int arr[4] = {1, 2, 3, 4};
{
Span<int> s{&arr[0], 2};
ASSERT_EQ(s.Length(), 2U);
ASSERT_EQ(s.data(), &arr[0]);
ASSERT_EQ(s[0], 1);
ASSERT_EQ(s[1], 2);
}
{
Span<int, 2> s{&arr[0], 2};
ASSERT_EQ(s.Length(), 2U);
ASSERT_EQ(s.data(), &arr[0]);
ASSERT_EQ(s[0], 1);
ASSERT_EQ(s[1], 2);
}
{
int* p = nullptr;
Span<int> s{p, static_cast<Span<int>::index_type>(0)};
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), SLICE_INT_PTR);
}
#if 0
{
int* p = nullptr;
auto workaround_macro = [=]() { Span<int> s{p, 2}; };
CHECK_THROW(workaround_macro(), fail_fast);
}
#endif
{
auto s = Span(&arr[0], 2);
ASSERT_EQ(s.Length(), 2U);
ASSERT_EQ(s.data(), &arr[0]);
ASSERT_EQ(s[0], 1);
ASSERT_EQ(s[1], 2);
}
{
int* p = nullptr;
auto s = Span(p, static_cast<Span<int>::index_type>(0));
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), SLICE_INT_PTR);
}
#if 0
{
int* p = nullptr;
auto workaround_macro = [=]() { Span(p, 2); };
CHECK_THROW(workaround_macro(), fail_fast);
}
#endif
}
SPAN_TEST(from_pointer_pointer_constructor) {
int arr[4] = {1, 2, 3, 4};
{
Span<int> s{&arr[0], &arr[2]};
ASSERT_EQ(s.Length(), 2U);
ASSERT_EQ(s.data(), &arr[0]);
ASSERT_EQ(s[0], 1);
ASSERT_EQ(s[1], 2);
}
{
Span<int, 2> s{&arr[0], &arr[2]};
ASSERT_EQ(s.Length(), 2U);
ASSERT_EQ(s.data(), &arr[0]);
ASSERT_EQ(s[0], 1);
ASSERT_EQ(s[1], 2);
}
{
Span<int> s{&arr[0], &arr[0]};
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), &arr[0]);
}
{
Span<int, 0> s{&arr[0], &arr[0]};
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), &arr[0]);
}
// this will fail the std::distance() precondition, which asserts on MSVC
// debug builds
//{
// auto workaround_macro = [&]() { Span<int> s{&arr[1], &arr[0]}; };
// CHECK_THROW(workaround_macro(), fail_fast);
//}
// this will fail the std::distance() precondition, which asserts on MSVC
// debug builds
//{
// int* p = nullptr;
// auto workaround_macro = [&]() { Span<int> s{&arr[0], p}; };
// CHECK_THROW(workaround_macro(), fail_fast);
//}
{
int* p = nullptr;
Span<int> s{p, p};
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), SLICE_INT_PTR);
}
{
int* p = nullptr;
Span<int, 0> s{p, p};
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), SLICE_INT_PTR);
}
// this will fail the std::distance() precondition, which asserts on MSVC
// debug builds
//{
// int* p = nullptr;
// auto workaround_macro = [&]() { Span<int> s{&arr[0], p}; };
// CHECK_THROW(workaround_macro(), fail_fast);
//}
{
auto s = Span(&arr[0], &arr[2]);
ASSERT_EQ(s.Length(), 2U);
ASSERT_EQ(s.data(), &arr[0]);
ASSERT_EQ(s[0], 1);
ASSERT_EQ(s[1], 2);
}
{
auto s = Span(&arr[0], &arr[0]);
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), &arr[0]);
}
{
int* p = nullptr;
auto s = Span(p, p);
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), SLICE_INT_PTR);
}
}
SPAN_TEST(from_array_constructor) {
int arr[5] = {1, 2, 3, 4, 5};
{
Span<int> s{arr};
ASSERT_EQ(s.Length(), 5U);
ASSERT_EQ(s.data(), &arr[0]);
}
{
Span<int, 5> s{arr};
ASSERT_EQ(s.Length(), 5U);
ASSERT_EQ(s.data(), &arr[0]);
}
int arr2d[2][3] = {{1, 2, 3}, {4, 5, 6}};
#ifdef CONFIRM_COMPILATION_ERRORS
{ Span<int, 6> s{arr}; }
{
Span<int, 0> s{arr};
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), &arr[0]);
}
{
Span<int> s{arr2d};
ASSERT_EQ(s.Length(), 6U);
ASSERT_EQ(s.data(), &arr2d[0][0]);
ASSERT_EQ(s[0], 1);
ASSERT_EQ(s[5], 6);
}
{
Span<int, 0> s{arr2d};
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), &arr2d[0][0]);
}
{ Span<int, 6> s{arr2d}; }
#endif
{
Span<int[3]> s{&(arr2d[0]), 1};
ASSERT_EQ(s.Length(), 1U);
ASSERT_EQ(s.data(), &arr2d[0]);
}
int arr3d[2][3][2] = {{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}};
#ifdef CONFIRM_COMPILATION_ERRORS
{
Span<int> s{arr3d};
ASSERT_EQ(s.Length(), 12U);
ASSERT_EQ(s.data(), &arr3d[0][0][0]);
ASSERT_EQ(s[0], 1);
ASSERT_EQ(s[11], 12);
}
{
Span<int, 0> s{arr3d};
ASSERT_EQ(s.Length(), 0U);
ASSERT_EQ(s.data(), &arr3d[0][0][0]);
}
{ Span<int, 11> s{arr3d}; }
{
Span<int, 12> s{arr3d};
ASSERT_EQ(s.Length(), 12U);
ASSERT_EQ(s.data(), &arr3d[0][0][0]);
ASSERT_EQ(s[0], 1);
ASSERT_EQ(s[5], 6);
}
#endif
{
Span<int[3][2]> s{&arr3d[0], 1};
ASSERT_EQ(s.Length(), 1U);
ASSERT_EQ(s.data(), &arr3d[0]);
}
{
auto s = Span(arr);
ASSERT_EQ(s.Length(), 5U);
ASSERT_EQ(s.data(), &arr[0]);
}
{
auto s = Span(&(arr2d[0]), 1);
ASSERT_EQ(s.Length(), 1U);
ASSERT_EQ(s.data(), &arr2d[0]);
}
{
auto s = Span(&arr3d[0], 1);
ASSERT_EQ(s.Length(), 1U);
ASSERT_EQ(s.data(), &arr3d[0]);
}
}
SPAN_TEST(from_dynamic_array_constructor) {
double(*arr)[3][4] = new double[100][3][4];
{
Span<double> s(&arr[0][0][0], 10);
ASSERT_EQ(s.Length(), 10U);
ASSERT_EQ(s.data(), &arr[0][0][0]);
}
{
auto s = Span(&arr[0][0][0], 10);
ASSERT_EQ(s.Length(), 10U);
ASSERT_EQ(s.data(), &arr[0][0][0]);
}
delete[] arr;
}
SPAN_TEST(from_std_array_constructor) {
std::array<int, 4> arr = {{1, 2, 3, 4}};
{
Span<int> s{arr};
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.size()));
ASSERT_EQ(s.data(), arr.data());
Span<const int> cs{arr};
ASSERT_EQ(cs.size(), narrow_cast<size_t>(arr.size()));
ASSERT_EQ(cs.data(), arr.data());
}
{
Span<int, 4> s{arr};
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.size()));
ASSERT_EQ(s.data(), arr.data());
Span<const int, 4> cs{arr};
ASSERT_EQ(cs.size(), narrow_cast<size_t>(arr.size()));
ASSERT_EQ(cs.data(), arr.data());
}
#ifdef CONFIRM_COMPILATION_ERRORS
{
Span<int, 2> s{arr};
ASSERT_EQ(s.size(), 2U);
ASSERT_EQ(s.data(), arr.data());
Span<const int, 2> cs{arr};
ASSERT_EQ(cs.size(), 2U);
ASSERT_EQ(cs.data(), arr.data());
}
{
Span<int, 0> s{arr};
ASSERT_EQ(s.size(), 0U);
ASSERT_EQ(s.data(), arr.data());
Span<const int, 0> cs{arr};
ASSERT_EQ(cs.size(), 0U);
ASSERT_EQ(cs.data(), arr.data());
}
{ Span<int, 5> s{arr}; }
{
auto get_an_array = []() -> std::array<int, 4> { return {1, 2, 3, 4}; };
auto take_a_Span = [](Span<int> s) { static_cast<void>(s); };
// try to take a temporary std::array
take_a_Span(get_an_array());
}
#endif
{
auto get_an_array = []() -> std::array<int, 4> { return {{1, 2, 3, 4}}; };
auto take_a_Span = [](Span<const int> s) { static_cast<void>(s); };
// try to take a temporary std::array
take_a_Span(get_an_array());
}
{
auto s = Span(arr);
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.size()));
ASSERT_EQ(s.data(), arr.data());
}
}
SPAN_TEST(from_const_std_array_constructor) {
const std::array<int, 4> arr = {{1, 2, 3, 4}};
{
Span<const int> s{arr};
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.size()));
ASSERT_EQ(s.data(), arr.data());
}
{
Span<const int, 4> s{arr};
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.size()));
ASSERT_EQ(s.data(), arr.data());
}
#ifdef CONFIRM_COMPILATION_ERRORS
{
Span<const int, 2> s{arr};
ASSERT_EQ(s.size(), 2U);
ASSERT_EQ(s.data(), arr.data());
}
{
Span<const int, 0> s{arr};
ASSERT_EQ(s.size(), 0U);
ASSERT_EQ(s.data(), arr.data());
}
{ Span<const int, 5> s{arr}; }
#endif
{
auto get_an_array = []() -> const std::array<int, 4> {
return {{1, 2, 3, 4}};
};
auto take_a_Span = [](Span<const int> s) { static_cast<void>(s); };
// try to take a temporary std::array
take_a_Span(get_an_array());
}
{
auto s = Span(arr);
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.size()));
ASSERT_EQ(s.data(), arr.data());
}
}
SPAN_TEST(from_std_array_const_constructor) {
std::array<const int, 4> arr = {{1, 2, 3, 4}};
{
Span<const int> s{arr};
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.size()));
ASSERT_EQ(s.data(), arr.data());
}
{
Span<const int, 4> s{arr};
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.size()));
ASSERT_EQ(s.data(), arr.data());
}
#ifdef CONFIRM_COMPILATION_ERRORS
{
Span<const int, 2> s{arr};
ASSERT_EQ(s.size(), 2U);
ASSERT_EQ(s.data(), arr.data());
}
{
Span<const int, 0> s{arr};
ASSERT_EQ(s.size(), 0U);
ASSERT_EQ(s.data(), arr.data());
}
{ Span<const int, 5> s{arr}; }
{ Span<int, 4> s{arr}; }
#endif
{
auto s = Span(arr);
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.size()));
ASSERT_EQ(s.data(), arr.data());
}
}
SPAN_TEST(from_mozilla_array_constructor) {
mozilla::Array<int, 4> arr(1, 2, 3, 4);
{
Span<int> s{arr};
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.cend() - arr.cbegin()));
ASSERT_EQ(s.data(), &arr[0]);
Span<const int> cs{arr};
ASSERT_EQ(cs.size(), narrow_cast<size_t>(arr.cend() - arr.cbegin()));
ASSERT_EQ(cs.data(), &arr[0]);
}
{
Span<int, 4> s{arr};
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.cend() - arr.cbegin()));
ASSERT_EQ(s.data(), &arr[0]);
Span<const int, 4> cs{arr};
ASSERT_EQ(cs.size(), narrow_cast<size_t>(arr.cend() - arr.cbegin()));
ASSERT_EQ(cs.data(), &arr[0]);
}
#ifdef CONFIRM_COMPILATION_ERRORS
{
Span<int, 2> s{arr};
ASSERT_EQ(s.size(), 2U);
ASSERT_EQ(s.data(), &arr[0]);
Span<const int, 2> cs{arr};
ASSERT_EQ(cs.size(), 2U);
ASSERT_EQ(cs.data(), &arr[0]);
}
{
Span<int, 0> s{arr};
ASSERT_EQ(s.size(), 0U);
ASSERT_EQ(s.data(), &arr[0]);
Span<const int, 0> cs{arr};
ASSERT_EQ(cs.size(), 0U);
ASSERT_EQ(cs.data(), &arr[0]);
}
{ Span<int, 5> s{arr}; }
{
auto get_an_array = []() -> mozilla::Array<int, 4> { return {1, 2, 3, 4}; };
auto take_a_Span = [](Span<int> s) { static_cast<void>(s); };
// try to take a temporary mozilla::Array
take_a_Span(get_an_array());
}
#endif
{
auto get_an_array = []() -> mozilla::Array<int, 4> { return {1, 2, 3, 4}; };
auto take_a_Span = [](Span<const int> s) { static_cast<void>(s); };
// try to take a temporary mozilla::Array
take_a_Span(get_an_array());
}
{
auto s = Span(arr);
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.cend() - arr.cbegin()));
ASSERT_EQ(s.data(), &arr[0]);
}
}
SPAN_TEST(from_const_mozilla_array_constructor) {
const mozilla::Array<int, 4> arr(1, 2, 3, 4);
{
Span<const int> s{arr};
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.cend() - arr.cbegin()));
ASSERT_EQ(s.data(), &arr[0]);
}
{
Span<const int, 4> s{arr};
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.cend() - arr.cbegin()));
ASSERT_EQ(s.data(), &arr[0]);
}
#ifdef CONFIRM_COMPILATION_ERRORS
{
Span<const int, 2> s{arr};
ASSERT_EQ(s.size(), 2U);
ASSERT_EQ(s.data(), &arr[0]);
}
{
Span<const int, 0> s{arr};
ASSERT_EQ(s.size(), 0U);
ASSERT_EQ(s.data(), &arr[0]);
}
{ Span<const int, 5> s{arr}; }
#endif
#if 0
{
auto get_an_array = []() -> const mozilla::Array<int, 4> {
return { 1, 2, 3, 4 };
};
auto take_a_Span = [](Span<const int> s) { static_cast<void>(s); };
// try to take a temporary mozilla::Array
take_a_Span(get_an_array());
}
#endif
{
auto s = Span(arr);
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.cend() - arr.cbegin()));
ASSERT_EQ(s.data(), &arr[0]);
}
}
SPAN_TEST(from_mozilla_array_const_constructor) {
mozilla::Array<const int, 4> arr(1, 2, 3, 4);
{
Span<const int> s{arr};
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.cend() - arr.cbegin()));
ASSERT_EQ(s.data(), &arr[0]);
}
{
Span<const int, 4> s{arr};
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.cend() - arr.cbegin()));
ASSERT_EQ(s.data(), &arr[0]);
}
#ifdef CONFIRM_COMPILATION_ERRORS
{
Span<const int, 2> s{arr};
ASSERT_EQ(s.size(), 2U);
ASSERT_EQ(s.data(), &arr[0]);
}
{
Span<const int, 0> s{arr};
ASSERT_EQ(s.size(), 0U);
ASSERT_EQ(s.data(), &arr[0]);
}
{ Span<const int, 5> s{arr}; }
{ Span<int, 4> s{arr}; }
#endif
{
auto s = Span(arr);
ASSERT_EQ(s.size(), narrow_cast<size_t>(arr.cend() - arr.cbegin()));
ASSERT_EQ(s.data(), &arr[0]);
}
}
SPAN_TEST(from_container_constructor) {
std::vector<int> v = {1, 2, 3};
const std::vector<int> cv = v;
{
AssertSpanOfThreeInts(v);
Span<int> s{v};
ASSERT_EQ(s.size(), narrow_cast<size_t>(v.size()));
ASSERT_EQ(s.data(), v.data());
Span<const int> cs{v};
ASSERT_EQ(cs.size(), narrow_cast<size_t>(v.size()));
ASSERT_EQ(cs.data(), v.data());
}
std::string str = "hello";
const std::string cstr = "hello";
{
#ifdef CONFIRM_COMPILATION_ERRORS
Span<char> s{str};
ASSERT_EQ(s.size(), narrow_cast<size_t>(str.size()));
ASSERT_EQ(s.data(), str.data());
#endif
Span<const char> cs{str};
ASSERT_EQ(cs.size(), narrow_cast<size_t>(str.size()));
ASSERT_EQ(cs.data(), str.data());
}
{
#ifdef CONFIRM_COMPILATION_ERRORS
Span<char> s{cstr};
#endif
Span<const char> cs{cstr};
ASSERT_EQ(cs.size(), narrow_cast<size_t>(cstr.size()));
ASSERT_EQ(cs.data(), cstr.data());
}
{
#ifdef CONFIRM_COMPILATION_ERRORS
auto get_temp_vector = []() -> std::vector<int> { return {}; };
auto use_Span = [](Span<int> s) { static_cast<void>(s); };
use_Span(get_temp_vector());
#endif
}
{
auto get_temp_vector = []() -> std::vector<int> { return {}; };
auto use_Span = [](Span<const int> s) { static_cast<void>(s); };
use_Span(get_temp_vector());
}
{
#ifdef CONFIRM_COMPILATION_ERRORS
auto get_temp_string = []() -> std::string { return {}; };
auto use_Span = [](Span<char> s) { static_cast<void>(s); };
use_Span(get_temp_string());
#endif
}
{
auto get_temp_string = []() -> std::string { return {}; };
auto use_Span = [](Span<const char> s) { static_cast<void>(s); };
use_Span(get_temp_string());
}
{
#ifdef CONFIRM_COMPILATION_ERRORS
auto get_temp_vector = []() -> const std::vector<int> { return {}; };
auto use_Span = [](Span<const char> s) { static_cast<void>(s); };
use_Span(get_temp_vector());
#endif
}
{
auto get_temp_string = []() -> const std::string { return {}; };
auto use_Span = [](Span<const char> s) { static_cast<void>(s); };
use_Span(get_temp_string());
}
{
#ifdef CONFIRM_COMPILATION_ERRORS
std::map<int, int> m;
Span<int> s{m};
#endif
}
{
auto s = Span(v);
ASSERT_EQ(s.size(), narrow_cast<size_t>(v.size()));
ASSERT_EQ(s.data(), v.data());
auto cs = Span(cv);
ASSERT_EQ(cs.size(), narrow_cast<size_t>(cv.size()));
ASSERT_EQ(cs.data(), cv.data());
}
}
SPAN_TEST(from_xpcom_collections) {
{
nsTArray<int> v;
v.AppendElement(1);
v.AppendElement(2);
v.AppendElement(3);
AssertSpanOfThreeInts(v);
Span<int> s{v};
ASSERT_EQ(s.size(), narrow_cast<size_t>(v.Length()));
ASSERT_EQ(s.data(), v.Elements());
ASSERT_EQ(s[2], 3);
Span<const int> cs{v};
ASSERT_EQ(cs.size(), narrow_cast<size_t>(v.Length()));
ASSERT_EQ(cs.data(), v.Elements());
ASSERT_EQ(cs[2], 3);
}
{
nsTArray<int> v;
v.AppendElement(1);
v.AppendElement(2);
v.AppendElement(3);
AssertSpanOfThreeInts(v);
auto s = Span(v);
ASSERT_EQ(s.size(), narrow_cast<size_t>(v.Length()));
ASSERT_EQ(s.data(), v.Elements());
ASSERT_EQ(s[2], 3);
}
{
AutoTArray<int, 5> v;
v.AppendElement(1);
v.AppendElement(2);
v.AppendElement(3);
AssertSpanOfThreeInts(v);
Span<int> s{v};
ASSERT_EQ(s.size(), narrow_cast<size_t>(v.Length()));
ASSERT_EQ(s.data(), v.Elements());
ASSERT_EQ(s[2], 3);
Span<const int> cs{v};
ASSERT_EQ(cs.size(), narrow_cast<size_t>(v.Length()));
ASSERT_EQ(cs.data(), v.Elements());
ASSERT_EQ(cs[2], 3);
}
{
AutoTArray<int, 5> v;
v.AppendElement(1);
v.AppendElement(2);
v.AppendElement(3);
AssertSpanOfThreeInts(v);
auto s = Span(v);
ASSERT_EQ(s.size(), narrow_cast<size_t>(v.Length()));
ASSERT_EQ(s.data(), v.Elements());
ASSERT_EQ(s[2], 3);
}
{
FallibleTArray<int> v;
*(v.AppendElement(fallible)) = 1;
*(v.AppendElement(fallible)) = 2;
*(v.AppendElement(fallible)) = 3;
AssertSpanOfThreeInts(v);
Span<int> s{v};
ASSERT_EQ(s.size(), narrow_cast<size_t>(v.Length()));
ASSERT_EQ(s.data(), v.Elements());
ASSERT_EQ(s[2], 3);
Span<const int> cs{v};
ASSERT_EQ(cs.size(), narrow_cast<size_t>(v.Length()));
ASSERT_EQ(cs.data(), v.Elements());
ASSERT_EQ(cs[2], 3);
}
{
FallibleTArray<int> v;
*(v.AppendElement(fallible)) = 1;
*(v.AppendElement(fallible)) = 2;
*(v.AppendElement(fallible)) = 3;
AssertSpanOfThreeInts(v);
auto s = Span(v);
ASSERT_EQ(s.size(), narrow_cast<size_t>(v.Length()));
ASSERT_EQ(s.data(), v.Elements());
ASSERT_EQ(s[2], 3);
}
{
nsAutoString str;
str.AssignLiteral(u"abc");
AssertSpanOfThreeChar16s(str);
AssertSpanOfThreeChar16sViaString(str);
Span<char16_t> s{str.GetMutableData()};
ASSERT_EQ(s.size(), narrow_cast<size_t>(str.Length()));
ASSERT_EQ(s.data(), str.BeginWriting());
ASSERT_EQ(s[2], 'c');
Span<const char16_t> cs{str};
ASSERT_EQ(cs.size(), narrow_cast<size_t>(str.Length()));
ASSERT_EQ(cs.data(), str.BeginReading());
ASSERT_EQ(cs[2], 'c');
}
{
nsAutoString str;
str.AssignLiteral(u"abc");
AssertSpanOfThreeChar16s(str);
AssertSpanOfThreeChar16sViaString(str);
auto s = Span(str);
ASSERT_EQ(s.size(), narrow_cast<size_t>(str.Length()));
ASSERT_EQ(s.data(), str.BeginReading());
ASSERT_EQ(s[2], 'c');
}
{
nsAutoCString str;
str.AssignLiteral("abc");
AssertSpanOfThreeChars(str);
AssertSpanOfThreeCharsViaString(str);
Span<const uint8_t> cs{str};
ASSERT_EQ(cs.size(), narrow_cast<size_t>(str.Length()));
ASSERT_EQ(cs.data(), reinterpret_cast<const uint8_t*>(str.BeginReading()));
ASSERT_EQ(cs[2], 'c');
}
{
nsAutoCString str;
str.AssignLiteral("abc");
AssertSpanOfThreeChars(str);
AssertSpanOfThreeCharsViaString(str);
auto s = Span(str);
ASSERT_EQ(s.size(), narrow_cast<size_t>(str.Length()));
ASSERT_EQ(s.data(), str.BeginReading());
ASSERT_EQ(s[2], 'c');
}
{
nsTArray<int> v;
v.AppendElement(1);
v.AppendElement(2);
v.AppendElement(3);
Range<int> r(v.Elements(), v.Length());
AssertSpanOfThreeInts(r);
Span<int> s{r};
ASSERT_EQ(s.size(), narrow_cast<size_t>(v.Length()));
ASSERT_EQ(s.data(), v.Elements());
ASSERT_EQ(s[2], 3);
Span<const int> cs{r};
ASSERT_EQ(cs.size(), narrow_cast<size_t>(v.Length()));
ASSERT_EQ(cs.data(), v.Elements());
ASSERT_EQ(cs[2], 3);
}
{
nsTArray<int> v;
v.AppendElement(1);
v.AppendElement(2);
v.AppendElement(3);
Range<int> r(v.Elements(), v.Length());
AssertSpanOfThreeInts(r);
auto s = Span(r);
ASSERT_EQ(s.size(), narrow_cast<size_t>(v.Length()));
ASSERT_EQ(s.data(), v.Elements());
ASSERT_EQ(s[2], 3);
}
}
SPAN_TEST(from_cstring) {
{
const char* str = nullptr;
auto cs = MakeStringSpan(str);
ASSERT_EQ(cs.size(), 0U);
}
{
const char* str = "abc";
auto cs = MakeStringSpan(str);
ASSERT_EQ(cs.size(), 3U);
ASSERT_EQ(cs.data(), str);
ASSERT_EQ(cs[2], 'c');
static_assert(MakeStringSpan("abc").size() == 3U);
static_assert(MakeStringSpan("abc")[2] == 'c');
#ifdef CONFIRM_COMPILATION_ERRORS
Span<const char> scccl("literal"); // error
Span<const char> sccel;
sccel = "literal"; // error
cs = Span("literal"); // error
#endif
}
{
char arr[4] = {'a', 'b', 'c', 0};
auto cs = MakeStringSpan(arr);
ASSERT_EQ(cs.size(), 3U);
ASSERT_EQ(cs.data(), arr);
ASSERT_EQ(cs[2], 'c');
cs = Span(arr);
ASSERT_EQ(cs.size(), 4U); // zero terminator is part of the array span.
ASSERT_EQ(cs.data(), arr);
ASSERT_EQ(cs[2], 'c');
ASSERT_EQ(cs[3], '\0'); // zero terminator is part of the array span.
#ifdef CONFIRM_COMPILATION_ERRORS
Span<char> scca(arr); // error
Span<const char> sccca(arr); // error
Span<const char> scccea;
scccea = arr; // error
#endif
}
{
const char16_t* str = nullptr;
auto cs = MakeStringSpan(str);
ASSERT_EQ(cs.size(), 0U);
}
{
char16_t arr[4] = {'a', 'b', 'c', 0};
const char16_t* str = arr;
auto cs = MakeStringSpan(str);
ASSERT_EQ(cs.size(), 3U);
ASSERT_EQ(cs.data(), str);
ASSERT_EQ(cs[2], 'c');
static_assert(MakeStringSpan(u"abc").size() == 3U);
static_assert(MakeStringSpan(u"abc")[2] == u'c');
cs = MakeStringSpan(arr);
ASSERT_EQ(cs.size(), 3U);
ASSERT_EQ(cs.data(), str);
ASSERT_EQ(cs[2], 'c');
cs = Span(arr);
ASSERT_EQ(cs.size(), 4U); // zero terminator is part of the array span.
ASSERT_EQ(cs.data(), str);
ASSERT_EQ(cs[2], 'c');
ASSERT_EQ(cs[3], '\0'); // zero terminator is part of the array span.
#ifdef CONFIRM_COMPILATION_ERRORS
Span<char16_t> scca(arr); // error
Span<const char16_t> scccea;
scccea = arr; // error
Span<const char16_t> scccl(u"literal"); // error
Span<const char16_t>* sccel;
*sccel = u"literal"; // error
cs = Span(u"literal"); // error
#endif
}
}
SPAN_TEST(from_convertible_Span_constructor){{Span<DerivedClass> avd;
Span<const DerivedClass> avcd = avd;
static_cast<void>(avcd);
}
{
#ifdef CONFIRM_COMPILATION_ERRORS
Span<DerivedClass> avd;
Span<BaseClass> avb = avd;
static_cast<void>(avb);
#endif
}
#ifdef CONFIRM_COMPILATION_ERRORS
{
Span<int> s;
Span<unsigned int> s2 = s;
static_cast<void>(s2);
}
{
Span<int> s;
Span<const unsigned int> s2 = s;
static_cast<void>(s2);
}
{
Span<int> s;
Span<short> s2 = s;
static_cast<void>(s2);
}
#endif
}
SPAN_TEST(copy_move_and_assignment) {
Span<int> s1;
ASSERT_TRUE(s1.empty());
int arr[] = {3, 4, 5};
Span<const int> s2 = arr;
ASSERT_EQ(s2.Length(), 3U);
ASSERT_EQ(s2.data(), &arr[0]);
s2 = s1;
ASSERT_TRUE(s2.empty());
auto get_temp_Span = [&]() -> Span<int> { return {&arr[1], 2}; };
auto use_Span = [&](Span<const int> s) {
ASSERT_EQ(s.Length(), 2U);
ASSERT_EQ(s.data(), &arr[1]);
};
use_Span(get_temp_Span());
s1 = get_temp_Span();
ASSERT_EQ(s1.Length(), 2U);
ASSERT_EQ(s1.data(), &arr[1]);
}
SPAN_TEST(first) {
int arr[5] = {1, 2, 3, 4, 5};
{
Span<int, 5> av = arr;
ASSERT_EQ(av.First<2>().Length(), 2U);
ASSERT_EQ(av.First(2).Length(), 2U);
}
{
Span<int, 5> av = arr;
ASSERT_EQ(av.First<0>().Length(), 0U);
ASSERT_EQ(av.First(0).Length(), 0U);
}
{
Span<int, 5> av = arr;
ASSERT_EQ(av.First<5>().Length(), 5U);
ASSERT_EQ(av.First(5).Length(), 5U);
}
#if 0
{
Span<int, 5> av = arr;
# ifdef CONFIRM_COMPILATION_ERRORS
ASSERT_EQ(av.First<6>().Length() , 6U);
ASSERT_EQ(av.First<-1>().Length() , -1);
# endif
CHECK_THROW(av.First(6).Length(), fail_fast);
}
#endif
{
Span<int> av;
ASSERT_EQ(av.First<0>().Length(), 0U);
ASSERT_EQ(av.First(0).Length(), 0U);
}
}
SPAN_TEST(last) {
int arr[5] = {1, 2, 3, 4, 5};
{
Span<int, 5> av = arr;
ASSERT_EQ(av.Last<2>().Length(), 2U);
ASSERT_EQ(av.Last(2).Length(), 2U);
}
{
Span<int, 5> av = arr;
ASSERT_EQ(av.Last<0>().Length(), 0U);
ASSERT_EQ(av.Last(0).Length(), 0U);
}
{
Span<int, 5> av = arr;
ASSERT_EQ(av.Last<5>().Length(), 5U);
ASSERT_EQ(av.Last(5).Length(), 5U);
}
#if 0
{
Span<int, 5> av = arr;
# ifdef CONFIRM_COMPILATION_ERRORS
ASSERT_EQ(av.Last<6>().Length() , 6U);
# endif
CHECK_THROW(av.Last(6).Length(), fail_fast);
}
#endif
{
Span<int> av;
ASSERT_EQ(av.Last<0>().Length(), 0U);
ASSERT_EQ(av.Last(0).Length(), 0U);
}
}
SPAN_TEST(from_to) {
int arr[5] = {1, 2, 3, 4, 5};
{
Span<int, 5> av = arr;
ASSERT_EQ(av.From(3).Length(), 2U);
ASSERT_EQ(av.From(2)[1], 4);
}
{
Span<int, 5> av = arr;
ASSERT_EQ(av.From(5).Length(), 0U);
}
{
Span<int, 5> av = arr;
ASSERT_EQ(av.From(0).Length(), 5U);
}
{
Span<int, 5> av = arr;
ASSERT_EQ(av.To(3).Length(), 3U);
ASSERT_EQ(av.To(3)[1], 2);
}
{
Span<int, 5> av = arr;
ASSERT_EQ(av.To(0).Length(), 0U);
}
{
Span<int, 5> av = arr;
ASSERT_EQ(av.To(5).Length(), 5U);
}
{
Span<int, 5> av = arr;
ASSERT_EQ(av.FromTo(1, 4).Length(), 3U);
ASSERT_EQ(av.FromTo(1, 4)[1], 3);
}
{
Span<int, 5> av = arr;
ASSERT_EQ(av.FromTo(2, 2).Length(), 0U);
}
{
Span<int, 5> av = arr;
ASSERT_EQ(av.FromTo(0, 5).Length(), 5U);
}
}
SPAN_TEST(Subspan) {
int arr[5] = {1, 2, 3, 4, 5};
{
Span<int, 5> av = arr;
ASSERT_EQ((av.Subspan<2, 2>().Length()), 2U);
ASSERT_EQ(av.Subspan(2, 2).Length(), 2U);
ASSERT_EQ(av.Subspan(2, 3).Length(), 3U);
}
{
Span<int, 5> av = arr;
ASSERT_EQ((av.Subspan<0, 0>().Length()), 0U);
ASSERT_EQ(av.Subspan(0, 0).Length(), 0U);
}
{
Span<int, 5> av = arr;
ASSERT_EQ((av.Subspan<0, 5>().Length()), 5U);
ASSERT_EQ(av.Subspan(0, 5).Length(), 5U);
CHECK_THROW(av.Subspan(0, 6).Length(), fail_fast);
CHECK_THROW(av.Subspan(1, 5).Length(), fail_fast);
}
{
Span<int, 5> av = arr;
ASSERT_EQ((av.Subspan<4, 0>().Length()), 0U);
ASSERT_EQ(av.Subspan(4, 0).Length(), 0U);
ASSERT_EQ(av.Subspan(5, 0).Length(), 0U);
CHECK_THROW(av.Subspan(6, 0).Length(), fail_fast);
}
{
Span<int> av;
ASSERT_EQ((av.Subspan<0, 0>().Length()), 0U);
ASSERT_EQ(av.Subspan(0, 0).Length(), 0U);
CHECK_THROW((av.Subspan<1, 0>().Length()), fail_fast);
}
{
Span<int> av;
ASSERT_EQ(av.Subspan(0).Length(), 0U);
CHECK_THROW(av.Subspan(1).Length(), fail_fast);
}
{
Span<int> av = arr;
ASSERT_EQ(av.Subspan(0).Length(), 5U);
ASSERT_EQ(av.Subspan(1).Length(), 4U);
ASSERT_EQ(av.Subspan(4).Length(), 1U);
ASSERT_EQ(av.Subspan(5).Length(), 0U);
CHECK_THROW(av.Subspan(6).Length(), fail_fast);
auto av2 = av.Subspan(1);
for (int i = 0; i < 4; ++i) ASSERT_EQ(av2[i], i + 2);
}
{
Span<int, 5> av = arr;
ASSERT_EQ(av.Subspan(0).Length(), 5U);
ASSERT_EQ(av.Subspan(1).Length(), 4U);
ASSERT_EQ(av.Subspan(4).Length(), 1U);
ASSERT_EQ(av.Subspan(5).Length(), 0U);
CHECK_THROW(av.Subspan(6).Length(), fail_fast);
auto av2 = av.Subspan(1);
for (int i = 0; i < 4; ++i) ASSERT_EQ(av2[i], i + 2);
}
}
SPAN_TEST(at_call) {
int arr[4] = {1, 2, 3, 4};
{
Span<int> s = arr;
ASSERT_EQ(s.at(0), 1);
CHECK_THROW(s.at(5), fail_fast);
}
{
int arr2d[2] = {1, 6};
Span<int, 2> s = arr2d;
ASSERT_EQ(s.at(0), 1);
ASSERT_EQ(s.at(1), 6);
CHECK_THROW(s.at(2), fail_fast);
}
}
SPAN_TEST(operator_function_call) {
int arr[4] = {1, 2, 3, 4};
{
Span<int> s = arr;
ASSERT_EQ(s(0), 1);
CHECK_THROW(s(5), fail_fast);
}
{
int arr2d[2] = {1, 6};
Span<int, 2> s = arr2d;
ASSERT_EQ(s(0), 1);
ASSERT_EQ(s(1), 6);
CHECK_THROW(s(2), fail_fast);
}
}
SPAN_TEST(iterator_default_init) {
Span<int>::iterator it1;
Span<int>::iterator it2;
ASSERT_EQ(it1, it2);
}
SPAN_TEST(const_iterator_default_init) {
Span<int>::const_iterator it1;
Span<int>::const_iterator it2;
ASSERT_EQ(it1, it2);
}
SPAN_TEST(iterator_conversions) {
Span<int>::iterator badIt;
Span<int>::const_iterator badConstIt;
ASSERT_EQ(badIt, badConstIt);
int a[] = {1, 2, 3, 4};
Span<int> s = a;
auto it = s.begin();
auto cit = s.cbegin();
ASSERT_EQ(it, cit);
ASSERT_EQ(cit, it);
Span<int>::const_iterator cit2 = it;
ASSERT_EQ(cit2, cit);
Span<int>::const_iterator cit3 = it + 4;
ASSERT_EQ(cit3, s.cend());
}
SPAN_TEST(iterator_comparisons) {
int a[] = {1, 2, 3, 4};
{
Span<int> s = a;
Span<int>::iterator it = s.begin();
auto it2 = it + 1;
Span<int>::const_iterator cit = s.cbegin();
ASSERT_EQ(it, cit);
ASSERT_EQ(cit, it);
ASSERT_EQ(it, it);
ASSERT_EQ(cit, cit);
ASSERT_EQ(cit, s.begin());
ASSERT_EQ(s.begin(), cit);
ASSERT_EQ(s.cbegin(), cit);
ASSERT_EQ(it, s.begin());
ASSERT_EQ(s.begin(), it);
ASSERT_NE(it, it2);
ASSERT_NE(it2, it);
ASSERT_NE(it, s.end());
ASSERT_NE(it2, s.end());
ASSERT_NE(s.end(), it);
ASSERT_NE(it2, cit);
ASSERT_NE(cit, it2);
ASSERT_LT(it, it2);
ASSERT_LE(it, it2);
ASSERT_LE(it2, s.end());
ASSERT_LT(it, s.end());
ASSERT_LE(it, cit);
ASSERT_LE(cit, it);
ASSERT_LT(cit, it2);
ASSERT_LE(cit, it2);
ASSERT_LT(cit, s.end());
ASSERT_LE(cit, s.end());
ASSERT_GT(it2, it);
ASSERT_GE(it2, it);
ASSERT_GT(s.end(), it2);
ASSERT_GE(s.end(), it2);
ASSERT_GT(it2, cit);
ASSERT_GE(it2, cit);
}
}
SPAN_TEST(begin_end) {
{
int a[] = {1, 2, 3, 4};
Span<int> s = a;
Span<int>::iterator it = s.begin();
Span<int>::iterator it2 = std::begin(s);
ASSERT_EQ(it, it2);
it = s.end();
it2 = std::end(s);
ASSERT_EQ(it, it2);
}
{
int a[] = {1, 2, 3, 4};
Span<int> s = a;
auto it = s.begin();
auto first = it;
ASSERT_EQ(it, first);
ASSERT_EQ(*it, 1);
auto beyond = s.end();
ASSERT_NE(it, beyond);
CHECK_THROW(*beyond, fail_fast);
ASSERT_EQ(beyond - first, 4);
ASSERT_EQ(first - first, 0);
ASSERT_EQ(beyond - beyond, 0);
++it;
ASSERT_EQ(it - first, 1);
ASSERT_EQ(*it, 2);
*it = 22;
ASSERT_EQ(*it, 22);
ASSERT_EQ(beyond - it, 3);
it = first;
ASSERT_EQ(it, first);
while (it != s.end()) {
*it = 5;
++it;
}
ASSERT_EQ(it, beyond);
ASSERT_EQ(it - beyond, 0);
for (auto& n : s) {
ASSERT_EQ(n, 5);
}
}
}
SPAN_TEST(cbegin_cend) {
#if 0
{
int a[] = { 1, 2, 3, 4 };
Span<int> s = a;
Span<int>::const_iterator cit = s.cbegin();
Span<int>::const_iterator cit2 = std::cbegin(s);
ASSERT_EQ(cit , cit2);
cit = s.cend();
cit2 = std::cend(s);
ASSERT_EQ(cit , cit2);
}
#endif
{
int a[] = {1, 2, 3, 4};
Span<int> s = a;
auto it = s.cbegin();
auto first = it;
ASSERT_EQ(it, first);
ASSERT_EQ(*it, 1);
auto beyond = s.cend();
ASSERT_NE(it, beyond);
CHECK_THROW(*beyond, fail_fast);
ASSERT_EQ(beyond - first, 4);
ASSERT_EQ(first - first, 0);
ASSERT_EQ(beyond - beyond, 0);
++it;
ASSERT_EQ(it - first, 1);
ASSERT_EQ(*it, 2);
ASSERT_EQ(beyond - it, 3);
int last = 0;
it = first;
ASSERT_EQ(it, first);
while (it != s.cend()) {
ASSERT_EQ(*it, last + 1);
last = *it;
++it;
}
ASSERT_EQ(it, beyond);
ASSERT_EQ(it - beyond, 0);
}
}
SPAN_TEST(rbegin_rend) {
{
int a[] = {1, 2, 3, 4};
Span<int> s = a;
auto it = s.rbegin();
auto first = it;
ASSERT_EQ(it, first);
ASSERT_EQ(*it, 4);
auto beyond = s.rend();
ASSERT_NE(it, beyond);
CHECK_THROW(*beyond, fail_fast);
ASSERT_EQ(beyond - first, 4);
ASSERT_EQ(first - first, 0);
ASSERT_EQ(beyond - beyond, 0);
++it;
ASSERT_EQ(it - first, 1);
ASSERT_EQ(*it, 3);
*it = 22;
ASSERT_EQ(*it, 22);
ASSERT_EQ(beyond - it, 3);
it = first;
ASSERT_EQ(it, first);
while (it != s.rend()) {
*it = 5;
++it;
}
ASSERT_EQ(it, beyond);
ASSERT_EQ(it - beyond, 0);
for (auto& n : s) {
ASSERT_EQ(n, 5);
}
}
}
SPAN_TEST(crbegin_crend) {
{
int a[] = {1, 2, 3, 4};
Span<int> s = a;
auto it = s.crbegin();
auto first = it;
ASSERT_EQ(it, first);
ASSERT_EQ(*it, 4);
auto beyond = s.crend();
ASSERT_NE(it, beyond);
CHECK_THROW(*beyond, fail_fast);
ASSERT_EQ(beyond - first, 4);
ASSERT_EQ(first - first, 0);
ASSERT_EQ(beyond - beyond, 0);
++it;
ASSERT_EQ(it - first, 1);
ASSERT_EQ(*it, 3);
ASSERT_EQ(beyond - it, 3);
it = first;
ASSERT_EQ(it, first);
int last = 5;
while (it != s.crend()) {
ASSERT_EQ(*it, last - 1);
last = *it;
++it;
}
ASSERT_EQ(it, beyond);
ASSERT_EQ(it - beyond, 0);
}
}
SPAN_TEST(comparison_operators) {
{
Span<int> s1 = nullptr;
Span<int> s2 = nullptr;
ASSERT_EQ(s1, s2);
ASSERT_FALSE(s1 != s2);
ASSERT_FALSE(s1 < s2);
ASSERT_LE(s1, s2);
ASSERT_FALSE(s1 > s2);
ASSERT_GE(s1, s2);
ASSERT_EQ(s2, s1);
ASSERT_FALSE(s2 != s1);
ASSERT_FALSE(s2 < s1);
ASSERT_LE(s2, s1);
ASSERT_FALSE(s2 > s1);
ASSERT_GE(s2, s1);
}
{
int arr[] = {2, 1};
Span<int> s1 = arr;
Span<int> s2 = arr;
ASSERT_EQ(s1, s2);
ASSERT_FALSE(s1 != s2);
ASSERT_FALSE(s1 < s2);
ASSERT_LE(s1, s2);
ASSERT_FALSE(s1 > s2);
ASSERT_GE(s1, s2);
ASSERT_EQ(s2, s1);
ASSERT_FALSE(s2 != s1);
ASSERT_FALSE(s2 < s1);
ASSERT_LE(s2, s1);
ASSERT_FALSE(s2 > s1);
ASSERT_GE(s2, s1);
}
{
int arr[] = {2, 1}; // bigger
Span<int> s1 = nullptr;
Span<int> s2 = arr;
ASSERT_NE(s1, s2);
ASSERT_NE(s2, s1);
ASSERT_NE(s1, s2);
ASSERT_NE(s2, s1);
ASSERT_LT(s1, s2);
ASSERT_FALSE(s2 < s1);
ASSERT_LE(s1, s2);
ASSERT_FALSE(s2 <= s1);
ASSERT_GT(s2, s1);
ASSERT_FALSE(s1 > s2);
ASSERT_GE(s2, s1);
ASSERT_FALSE(s1 >= s2);
}
{
int arr1[] = {1, 2};
int arr2[] = {1, 2};
Span<int> s1 = arr1;
Span<int> s2 = arr2;
ASSERT_EQ(s1, s2);
ASSERT_FALSE(s1 != s2);
ASSERT_FALSE(s1 < s2);
ASSERT_LE(s1, s2);
ASSERT_FALSE(s1 > s2);
ASSERT_GE(s1, s2);
ASSERT_EQ(s2, s1);
ASSERT_FALSE(s2 != s1);
ASSERT_FALSE(s2 < s1);
ASSERT_LE(s2, s1);
ASSERT_FALSE(s2 > s1);
ASSERT_GE(s2, s1);
}
{
int arr[] = {1, 2, 3};
AssertSpanOfThreeInts(arr);
Span<int> s1 = {&arr[0], 2}; // shorter
Span<int> s2 = arr; // longer
ASSERT_NE(s1, s2);
ASSERT_NE(s2, s1);
ASSERT_NE(s1, s2);
ASSERT_NE(s2, s1);
ASSERT_LT(s1, s2);
ASSERT_FALSE(s2 < s1);
ASSERT_LE(s1, s2);
ASSERT_FALSE(s2 <= s1);
ASSERT_GT(s2, s1);
ASSERT_FALSE(s1 > s2);
ASSERT_GE(s2, s1);
ASSERT_FALSE(s1 >= s2);
}
{
int arr1[] = {1, 2}; // smaller
int arr2[] = {2, 1}; // bigger
Span<int> s1 = arr1;
Span<int> s2 = arr2;
ASSERT_NE(s1, s2);
ASSERT_NE(s2, s1);
ASSERT_NE(s1, s2);
ASSERT_NE(s2, s1);
ASSERT_LT(s1, s2);
ASSERT_FALSE(s2 < s1);
ASSERT_LE(s1, s2);
ASSERT_FALSE(s2 <= s1);
ASSERT_GT(s2, s1);
ASSERT_FALSE(s1 > s2);
ASSERT_GE(s2, s1);
ASSERT_FALSE(s1 >= s2);
}
}
SPAN_TEST(as_bytes) {
int a[] = {1, 2, 3, 4};
{
Span<const int> s = a;
ASSERT_EQ(s.Length(), 4U);
Span<const uint8_t> bs = AsBytes(s);
ASSERT_EQ(static_cast<const void*>(bs.data()),
static_cast<const void*>(s.data()));
ASSERT_EQ(bs.Length(), s.LengthBytes());
}
{
Span<int> s;
auto bs = AsBytes(s);
ASSERT_EQ(bs.Length(), s.Length());
ASSERT_EQ(bs.Length(), 0U);
ASSERT_EQ(bs.size_bytes(), 0U);
ASSERT_EQ(static_cast<const void*>(bs.data()),
static_cast<const void*>(s.data()));
ASSERT_EQ(bs.data(), reinterpret_cast<const uint8_t*>(SLICE_INT_PTR));
}
{
Span<int> s = a;
auto bs = AsBytes(s);
ASSERT_EQ(static_cast<const void*>(bs.data()),
static_cast<const void*>(s.data()));
ASSERT_EQ(bs.Length(), s.LengthBytes());
}
}
SPAN_TEST(as_writable_bytes) {
int a[] = {1, 2, 3, 4};
{
#ifdef CONFIRM_COMPILATION_ERRORS
// you should not be able to get writeable bytes for const objects
Span<const int> s = a;
ASSERT_EQ(s.Length(), 4U);
Span<const byte> bs = AsWritableBytes(s);
ASSERT_EQ(static_cast<void*>(bs.data()), static_cast<void*>(s.data()));
ASSERT_EQ(bs.Length(), s.LengthBytes());
#endif
}
{
Span<int> s;
auto bs = AsWritableBytes(s);
ASSERT_EQ(bs.Length(), s.Length());
ASSERT_EQ(bs.Length(), 0U);
ASSERT_EQ(bs.size_bytes(), 0U);
ASSERT_EQ(static_cast<void*>(bs.data()), static_cast<void*>(s.data()));
ASSERT_EQ(bs.data(), reinterpret_cast<uint8_t*>(SLICE_INT_PTR));
}
{
Span<int> s = a;
auto bs = AsWritableBytes(s);
ASSERT_EQ(static_cast<void*>(bs.data()), static_cast<void*>(s.data()));
ASSERT_EQ(bs.Length(), s.LengthBytes());
}
}
SPAN_TEST(as_chars) {
const uint8_t a[] = {1, 2, 3, 4};
Span<const uint8_t> u = Span(a);
Span<const char> c = AsChars(u);
ASSERT_EQ(static_cast<const void*>(u.data()),
static_cast<const void*>(c.data()));
ASSERT_EQ(u.size(), c.size());
}
SPAN_TEST(as_writable_chars) {
uint8_t a[] = {1, 2, 3, 4};
Span<uint8_t> u = Span(a);
Span<char> c = AsWritableChars(u);
ASSERT_EQ(static_cast<void*>(u.data()), static_cast<void*>(c.data()));
ASSERT_EQ(u.size(), c.size());
}
SPAN_TEST(fixed_size_conversions) {
int arr[] = {1, 2, 3, 4};
// converting to an Span from an equal size array is ok
Span<int, 4> s4 = arr;
ASSERT_EQ(s4.Length(), 4U);
// converting to dynamic_range is always ok
{
Span<int> s = s4;
ASSERT_EQ(s.Length(), s4.Length());
static_cast<void>(s);
}
// initialization or assignment to static Span that REDUCES size is NOT ok
#ifdef CONFIRM_COMPILATION_ERRORS
{ Span<int, 2> s = arr; }
{
Span<int, 2> s2 = s4;
static_cast<void>(s2);
}
#endif
#if 0
// even when done dynamically
{
Span<int> s = arr;
auto f = [&]() {
Span<int, 2> s2 = s;
static_cast<void>(s2);
};
CHECK_THROW(f(), fail_fast);
}
#endif
// but doing so explicitly is ok
// you can convert statically
{
Span<int, 2> s2 = {arr, 2};
static_cast<void>(s2);
}
{
Span<int, 1> s1 = s4.First<1>();
static_cast<void>(s1);
}
// ...or dynamically
{
// NB: implicit conversion to Span<int,1> from Span<int>
Span<int, 1> s1 = s4.First(1);
static_cast<void>(s1);
}
#if 0
// initialization or assignment to static Span that requires size INCREASE is not ok.
int arr2[2] = {1, 2};
#endif
#ifdef CONFIRM_COMPILATION_ERRORS
{ Span<int, 4> s3 = arr2; }
{
Span<int, 2> s2 = arr2;
Span<int, 4> s4a = s2;
}
#endif
#if 0
{
auto f = [&]() {
Span<int, 4> _s4 = {arr2, 2};
static_cast<void>(_s4);
};
CHECK_THROW(f(), fail_fast);
}
// this should fail - we are trying to assign a small dynamic Span to a fixed_size larger one
Span<int> av = arr2;
auto f = [&]() {
Span<int, 4> _s4 = av;
static_cast<void>(_s4);
};
CHECK_THROW(f(), fail_fast);
#endif
}
#if 0
SPAN_TEST(interop_with_std_regex)
{
char lat[] = { '1', '2', '3', '4', '5', '6', 'E', 'F', 'G' };
Span<char> s = lat;
auto f_it = s.begin() + 7;
std::match_results<Span<char>::iterator> match;
std::regex_match(s.begin(), s.end(), match, std::regex(".*"));
ASSERT_EQ(match.ready());
ASSERT_TRUE(!match.empty());
ASSERT_TRUE(match[0].matched);
ASSERT_TRUE(match[0].first , s.begin());
ASSERT_EQ(match[0].second , s.end());
std::regex_search(s.begin(), s.end(), match, std::regex("F"));
ASSERT_TRUE(match.ready());
ASSERT_TRUE(!match.empty());
ASSERT_TRUE(match[0].matched);
ASSERT_EQ(match[0].first , f_it);
ASSERT_EQ(match[0].second , (f_it + 1));
}
SPAN_TEST(interop_with_gsl_at)
{
int arr[5] = { 1, 2, 3, 4, 5 };
Span<int> s{ arr };
ASSERT_EQ(at(s, 0) , 1 );
ASSERT_EQ(at(s, 1) , 2U);
}
#endif
SPAN_TEST(default_constructible) {
ASSERT_TRUE((std::is_default_constructible<Span<int>>::value));
ASSERT_TRUE((std::is_default_constructible<Span<int, 0>>::value));
ASSERT_TRUE((!std::is_default_constructible<Span<int, 42>>::value));
}
SPAN_TEST(type_inference) {
static constexpr int arr[5] = {1, 2, 3, 4, 5};
constexpr auto s = Span{arr};
static_assert(std::is_same_v<const Span<const int, 5>, decltype(s)>);
static_assert(arr == s.Elements());
}
SPAN_TEST(split_at_dynamic_with_dynamic_extent) {
static constexpr int arr[5] = {1, 2, 3, 4, 5};
constexpr Span<const int> s = Span{arr};
{ // Split at begin.
constexpr auto splitAt0Result = s.SplitAt(0);
static_assert(
std::is_same_v<Span<const int>, decltype(splitAt0Result.first)>);
static_assert(
std::is_same_v<Span<const int>, decltype(splitAt0Result.second)>);
ASSERT_EQ(s.Elements(), splitAt0Result.second.Elements());
ASSERT_EQ(0u, splitAt0Result.first.Length());
ASSERT_EQ(5u, splitAt0Result.second.Length());
}
{ // Split at end.
constexpr auto splitAt5Result = s.SplitAt(s.Length());
static_assert(
std::is_same_v<Span<const int>, decltype(splitAt5Result.first)>);
static_assert(
std::is_same_v<Span<const int>, decltype(splitAt5Result.second)>);
ASSERT_EQ(s.Elements(), splitAt5Result.first.Elements());
ASSERT_EQ(5u, splitAt5Result.first.Length());
ASSERT_EQ(0u, splitAt5Result.second.Length());
}
{
// Split inside.
constexpr auto splitAt3Result = s.SplitAt(3);
static_assert(
std::is_same_v<Span<const int>, decltype(splitAt3Result.first)>);
static_assert(
std::is_same_v<Span<const int>, decltype(splitAt3Result.second)>);
ASSERT_EQ(s.Elements(), splitAt3Result.first.Elements());
ASSERT_EQ(s.Elements() + 3, splitAt3Result.second.Elements());
ASSERT_EQ(3u, splitAt3Result.first.Length());
ASSERT_EQ(2u, splitAt3Result.second.Length());
}
}
SPAN_TEST(split_at_dynamic_with_static_extent) {
static constexpr int arr[5] = {1, 2, 3, 4, 5};
constexpr auto s = Span{arr};
{
// Split at begin.
constexpr auto splitAt0Result = s.SplitAt(0);
static_assert(
std::is_same_v<Span<const int>, decltype(splitAt0Result.first)>);
static_assert(
std::is_same_v<Span<const int>, decltype(splitAt0Result.second)>);
ASSERT_EQ(s.Elements(), splitAt0Result.second.Elements());
}
{
// Split at end.
constexpr auto splitAt5Result = s.SplitAt(s.Length());
static_assert(
std::is_same_v<Span<const int>, decltype(splitAt5Result.first)>);
static_assert(
std::is_same_v<Span<const int>, decltype(splitAt5Result.second)>);
ASSERT_EQ(s.Elements(), splitAt5Result.first.Elements());
}
{
// Split inside.
constexpr auto splitAt3Result = s.SplitAt(3);
static_assert(
std::is_same_v<Span<const int>, decltype(splitAt3Result.first)>);
static_assert(
std::is_same_v<Span<const int>, decltype(splitAt3Result.second)>);
ASSERT_EQ(s.Elements(), splitAt3Result.first.Elements());
ASSERT_EQ(s.Elements() + 3, splitAt3Result.second.Elements());
}
}
SPAN_TEST(split_at_static) {
static constexpr int arr[5] = {1, 2, 3, 4, 5};
constexpr auto s = Span{arr};
// Split at begin.
constexpr auto splitAt0Result = s.SplitAt<0>();
static_assert(
std::is_same_v<Span<const int, 0>, decltype(splitAt0Result.first)>);
static_assert(
std::is_same_v<Span<const int, 5>, decltype(splitAt0Result.second)>);
static_assert(splitAt0Result.second.Elements() == s.Elements());
// Split at end.
constexpr auto splitAt5Result = s.SplitAt<s.Length()>();
static_assert(std::is_same_v<Span<const int, s.Length()>,
decltype(splitAt5Result.first)>);
static_assert(
std::is_same_v<Span<const int, 0>, decltype(splitAt5Result.second)>);
static_assert(splitAt5Result.first.Elements() == s.Elements());
// Split inside.
constexpr auto splitAt3Result = s.SplitAt<3>();
static_assert(
std::is_same_v<Span<const int, 3>, decltype(splitAt3Result.first)>);
static_assert(
std::is_same_v<Span<const int, 2>, decltype(splitAt3Result.second)>);
static_assert(splitAt3Result.first.Elements() == s.Elements());
static_assert(splitAt3Result.second.Elements() == s.Elements() + 3);
}
SPAN_TEST(as_const_dynamic) {
static int arr[5] = {1, 2, 3, 4, 5};
auto span = Span{arr, 5};
auto constSpan = span.AsConst();
static_assert(std::is_same_v<Span<const int>, decltype(constSpan)>);
}
SPAN_TEST(as_const_static) {
{
static constexpr int constArr[5] = {1, 2, 3, 4, 5};
constexpr auto span = Span{constArr}; // is already a Span<const int>
constexpr auto constSpan = span.AsConst();
static_assert(
std::is_same_v<const Span<const int, 5>, decltype(constSpan)>);
}
{
static int arr[5] = {1, 2, 3, 4, 5};
auto span = Span{arr};
auto constSpan = span.AsConst();
static_assert(std::is_same_v<Span<const int, 5>, decltype(constSpan)>);
}
}
SPAN_TEST(construct_from_iterators_dynamic) {
const int constArr[5] = {1, 2, 3, 4, 5};
auto constSpan = Span{constArr};
// const from const
{
const auto wholeSpan = Span{constSpan.cbegin(), constSpan.cend()};
static_assert(std::is_same_v<decltype(wholeSpan), const Span<const int>>);
ASSERT_TRUE(constSpan == wholeSpan);
const auto emptyBeginSpan = Span{constSpan.cbegin(), constSpan.cbegin()};
ASSERT_TRUE(emptyBeginSpan.IsEmpty());
const auto emptyEndSpan = Span{constSpan.cend(), constSpan.cend()};
ASSERT_TRUE(emptyEndSpan.IsEmpty());
const auto subSpan = Span{constSpan.cbegin() + 1, constSpan.cend() - 1};
ASSERT_EQ(constSpan.Length() - 2, subSpan.Length());
ASSERT_EQ(constSpan.Elements() + 1, subSpan.Elements());
}
int arr[5] = {1, 2, 3, 4, 5};
auto span = Span{arr};
// const from non-const
{
const auto wholeSpan = Span{span.cbegin(), span.cend()};
static_assert(std::is_same_v<decltype(wholeSpan), const Span<const int>>);
// XXX Can't use span == wholeSpan because of difference in constness.
ASSERT_EQ(span.Elements(), wholeSpan.Elements());
ASSERT_EQ(span.Length(), wholeSpan.Length());
const auto emptyBeginSpan = Span{span.cbegin(), span.cbegin()};
ASSERT_TRUE(emptyBeginSpan.IsEmpty());
const auto emptyEndSpan = Span{span.cend(), span.cend()};
ASSERT_TRUE(emptyEndSpan.IsEmpty());
const auto subSpan = Span{span.cbegin() + 1, span.cend() - 1};
ASSERT_EQ(span.Length() - 2, subSpan.Length());
ASSERT_EQ(span.Elements() + 1, subSpan.Elements());
}
// non-const from non-const
{
const auto wholeSpan = Span{span.begin(), span.end()};
static_assert(std::is_same_v<decltype(wholeSpan), const Span<int>>);
ASSERT_TRUE(span == wholeSpan);
const auto emptyBeginSpan = Span{span.begin(), span.begin()};
ASSERT_TRUE(emptyBeginSpan.IsEmpty());
const auto emptyEndSpan = Span{span.end(), span.end()};
ASSERT_TRUE(emptyEndSpan.IsEmpty());
const auto subSpan = Span{span.begin() + 1, span.end() - 1};
ASSERT_EQ(span.Length() - 2, subSpan.Length());
}
}
SPAN_TEST(construct_from_iterators_static) {
static constexpr int arr[5] = {1, 2, 3, 4, 5};
constexpr auto constSpan = Span{arr};
// const
{
const auto wholeSpan = Span{constSpan.cbegin(), constSpan.cend()};
static_assert(std::is_same_v<decltype(wholeSpan), const Span<const int>>);
ASSERT_TRUE(constSpan == wholeSpan);
const auto emptyBeginSpan = Span{constSpan.cbegin(), constSpan.cbegin()};
ASSERT_TRUE(emptyBeginSpan.IsEmpty());
const auto emptyEndSpan = Span{constSpan.cend(), constSpan.cend()};
ASSERT_TRUE(emptyEndSpan.IsEmpty());
const auto subSpan = Span{constSpan.cbegin() + 1, constSpan.cend() - 1};
ASSERT_EQ(constSpan.Length() - 2, subSpan.Length());
ASSERT_EQ(constSpan.Elements() + 1, subSpan.Elements());
}
}
SPAN_TEST(construct_from_container_with_type_deduction) {
std::vector<int> vec = {1, 2, 3, 4, 5};
// from const
{
const auto& constVecRef = vec;
auto span = Span{constVecRef};
static_assert(std::is_same_v<decltype(span), Span<const int>>);
}
// from non-const
{
auto span = Span{vec};
static_assert(std::is_same_v<decltype(span), Span<int>>);
}
}