From fca89c2118997a746804f88125c24e8454a7884d Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Mon, 12 Jul 2021 08:48:20 +0000 Subject: [PATCH] Backport span from C++20 Does not support ranges and construction from arbitrary contiguous iterators as both need C++20 concepts for an adequate implementation. --- .../runtime/src/main/cpp/cpp_support/Span.hpp | 295 +++++ .../src/main/cpp/cpp_support/SpanTest.cpp | 1006 +++++++++++++++++ 2 files changed, 1301 insertions(+) create mode 100644 kotlin-native/runtime/src/main/cpp/cpp_support/Span.hpp create mode 100644 kotlin-native/runtime/src/main/cpp/cpp_support/SpanTest.cpp diff --git a/kotlin-native/runtime/src/main/cpp/cpp_support/Span.hpp b/kotlin-native/runtime/src/main/cpp/cpp_support/Span.hpp new file mode 100644 index 00000000000..d2b13d1b2f0 --- /dev/null +++ b/kotlin-native/runtime/src/main/cpp/cpp_support/Span.hpp @@ -0,0 +1,295 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the LICENSE file. + */ + +#ifndef RUNTIME_CPP_SUPPORT_SPAN_H +#define RUNTIME_CPP_SUPPORT_SPAN_H + +#include +#include +#include +#include + +#include "KAssert.h" + +// Modelling https://en.cppreference.com/w/cpp/container/span from C++20. + +namespace kotlin { +namespace std_support { + +namespace internal { + +template +inline constexpr bool ConvertibleForSpan = std::is_convertible_v; + +template +using EnableIfConvertibleForSpan = std::enable_if_t, std::nullptr_t>; + +} // namespace internal + +inline constexpr std::size_t dynamic_extent = std::numeric_limits::max(); + +template +class span { +public: + using element_type = T; + using value_type = std::remove_cv_t; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using iterator = T*; + using reverse_iterator = std::reverse_iterator; + + static constexpr std::size_t extent = Extent; + + template = nullptr> + constexpr span() noexcept : data_(nullptr) {} + + // TODO: Instead of U* it should just be a `contiguos_iterator` with a deduction guide. + template = nullptr> + constexpr explicit span(U* first, size_type count) : data_(first) { + RuntimeAssert(count == Extent, "Mismatched count=%zu, expected %zu", count, Extent); + } + + // TODO: Instead of U* it should just be a `contiguos_iterator` with a deduction guide. + template = nullptr> + constexpr explicit span(U* first, U* last) : data_(first) { + auto count = std::distance(first, last); + RuntimeAssert(count == Extent, "Mismatched count=%zu, expected %zu", count, Extent); + } + + constexpr span(element_type (&arr)[Extent]) noexcept : data_(arr) {} + + template = nullptr> + constexpr span(std::array& arr) noexcept : data_(arr.data()) {} + + template = nullptr> + constexpr span(const std::array& arr) noexcept : data_(arr.data()) {} + + // TODO: Constructor from a range with a deduction guide. + + template = nullptr> + constexpr span(const span& source) noexcept : data_(source.data()) {} + + template = nullptr> + constexpr explicit span(const span& source) noexcept : data_(source.data()) { + RuntimeAssert(source.size() == Extent, "Mismatched count=%zu, expected %zu", source.size(), Extent); + } + + constexpr span(const span& other) noexcept = default; + + constexpr span& operator=(const span& other) noexcept = default; + + constexpr iterator begin() const noexcept { return data_; } + constexpr iterator end() const noexcept { return data_ + size(); } + + constexpr reverse_iterator rbegin() const noexcept { return std::reverse_iterator(end()); } + constexpr reverse_iterator rend() const noexcept { return std::reverse_iterator(begin()); } + + constexpr reference front() const { + RuntimeAssert(!empty(), "Calling front on an empty span"); + return *begin(); + } + constexpr reference back() const { + RuntimeAssert(!empty(), "Calling back on an empty span"); + return *(end() - 1); + } + constexpr reference operator[](size_type idx) const { + RuntimeAssert(idx < size(), "Indexing at %zu on a span of size %zu", idx, size()); + return data()[idx]; + } + + constexpr pointer data() const noexcept { return data_; } + + constexpr size_type size() const noexcept { return Extent; } + constexpr size_type size_bytes() const noexcept { return Extent * sizeof(element_type); } + [[nodiscard]] constexpr bool empty() const noexcept { return Extent == 0; } + + template + constexpr span first() const { + static_assert(Count <= Extent, "Count must be smaller than Extent"); + return span(data_, Count); + } + + constexpr span first(size_type count) const { + RuntimeAssert(count <= size(), "count %zu must be smaller than size %zu", count, size()); + return span(data_, count); + } + + template + constexpr span last() const { + static_assert(Count <= Extent, "Count must be smaller than Extent"); + return span(data_ + size() - Count, Count); + } + + constexpr span last(size_type count) const { + RuntimeAssert(count <= size(), "count %zu must be smaller than size %zu", count, size()); + return span(data_ + size() - count, count); + } + + template + constexpr span subspan() const { + static_assert(Offset <= Extent, "Offset must be smaller than Extent"); + static_assert(Count == dynamic_extent || Count <= Extent - Offset, "Count must be smaller than Extent - Offset"); + + return span < element_type, + Count != dynamic_extent ? Count : Extent - Offset > (data_ + Offset, Count == dynamic_extent ? size() - Offset : Count); + } + + constexpr span subspan(size_type offset, size_type count = dynamic_extent) const { + RuntimeAssert(offset <= size(), "offset %zu must be smaller than size %zu", offset, size()); + RuntimeAssert( + count == dynamic_extent || count <= size() - offset, "count %zu must be smaller than size %zu - offset %zu", count, size(), + offset); + + if (count == dynamic_extent) { + return span(data() + offset, size() - offset); + } + + return span(data() + offset, count); + } + +private: + T* data_; +}; + +template +class span { +public: + using element_type = T; + using value_type = std::remove_cv_t; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using pointer = T*; + using const_pointer = const T*; + using reference = T&; + using const_reference = const T&; + using iterator = T*; + using reverse_iterator = std::reverse_iterator; + + static constexpr std::size_t extent = dynamic_extent; + + constexpr span() noexcept : data_(nullptr), size_(0) {} + + // TODO: Instead of U* it should just be a `contiguos_iterator` with a deduction guide. + template = nullptr> + constexpr span(U* first, size_type count) : data_(first), size_(count) {} + + // TODO: Instead of U* it should just be a `contiguos_iterator` with a deduction guide. + template = nullptr> + constexpr span(U* first, U* last) : data_(first), size_(std::distance(first, last)) {} + + template + constexpr span(element_type (&arr)[N]) noexcept : data_(arr), size_(N) {} + + template = nullptr> + constexpr span(std::array& arr) noexcept : data_(arr.data()), size_(N) {} + + template = nullptr> + constexpr span(const std::array& arr) noexcept : data_(arr.data()), size_(N) {} + + // TODO: Constructor from a range with a deduction guide. + + template = nullptr> + constexpr span(const span& source) noexcept : data_(source.data()), size_(source.size()) {} + + constexpr span(const span& other) noexcept = default; + + constexpr span& operator=(const span& other) noexcept = default; + + constexpr iterator begin() const noexcept { return data_; } + constexpr iterator end() const noexcept { return data_ + size(); } + + constexpr reverse_iterator rbegin() const noexcept { return std::reverse_iterator(end()); } + constexpr reverse_iterator rend() const noexcept { return std::reverse_iterator(begin()); } + + constexpr reference front() const { + RuntimeAssert(!empty(), "Calling front on an empty span"); + return *begin(); + } + constexpr reference back() const { + RuntimeAssert(!empty(), "Calling back on an empty span"); + return *(end() - 1); + } + constexpr reference operator[](size_type idx) const { + RuntimeAssert(idx < size(), "Indexing at %zu on a span of size %zu", idx, size()); + return data()[idx]; + } + + constexpr pointer data() const noexcept { return data_; } + + constexpr size_type size() const noexcept { return size_; } + constexpr size_type size_bytes() const noexcept { return size_ * sizeof(element_type); } + [[nodiscard]] constexpr bool empty() const noexcept { return size_ == 0; } + + template + constexpr span first() const { + RuntimeAssert(Count <= size(), "Count %zu must be smaller than size %zu", Count, size()); + return span(data_, Count); + } + + constexpr span first(size_type count) const { + RuntimeAssert(count <= size(), "count %zu must be smaller than size %zu", count, size()); + return span(data_, count); + } + + template + constexpr span last() const { + RuntimeAssert(Count <= size(), "Count %zu must be smaller than size %zu", Count, size()); + return span(data_ + size() - Count, Count); + } + + constexpr span last(size_type count) const { + RuntimeAssert(count <= size(), "count %zu must be smaller than size %zu", count, size()); + return span(data_ + size() - count, count); + } + + template + constexpr span subspan() const { + RuntimeAssert(Offset <= size(), "Offset %zu must be smaller than size %zu", Offset, size()); + RuntimeAssert( + Count == dynamic_extent || Count <= size() - Offset, "Count %zu must be smaller than size %zu - Offset %zu", Count, size(), + Offset); + + return span(data_ + Offset, Count == dynamic_extent ? size() - Offset : Count); + } + + constexpr span subspan(size_type offset, size_type count = dynamic_extent) const { + RuntimeAssert(offset <= size(), "offset %zu must be smaller than size %zu", offset, size()); + RuntimeAssert( + count == dynamic_extent || count <= size() - offset, "count %zu must be smaller than size %zu - offset %zu", count, size(), + offset); + + if (count == dynamic_extent) { + return span(data() + offset, size() - offset); + } + + return span(data() + offset, count); + } + +private: + T* data_; + size_type size_; +}; + +template +span(T (&)[N]) -> span; + +template +span(std::array&) -> span; + +template +span(const std::array&) -> span; + +// TODO: as_bytes, as_writable_bytes + +// TODO: Tags for ranges. + +} // namespace std_support +} // namespace kotlin + +#endif // RUNTIME_CPP_SUPPORT_SPAN_H diff --git a/kotlin-native/runtime/src/main/cpp/cpp_support/SpanTest.cpp b/kotlin-native/runtime/src/main/cpp/cpp_support/SpanTest.cpp new file mode 100644 index 00000000000..d930858e6e9 --- /dev/null +++ b/kotlin-native/runtime/src/main/cpp/cpp_support/SpanTest.cpp @@ -0,0 +1,1006 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the LICENSE file. + */ + +#include "Span.hpp" + +#include +#include + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace kotlin; + +namespace { + +struct BaseType { + int field1; + + bool operator==(const BaseType& rhs) const { return field1 == rhs.field1; } +}; + +struct DerivedType : public BaseType { + int field2; +}; + +template +void ExpectEmpty(const Span& s, T data) { + EXPECT_TRUE(s.empty()); + EXPECT_THAT(s.data(), data); + EXPECT_THAT(s.size(), 0); + EXPECT_THAT(s.size_bytes(), 0); + EXPECT_THAT(std::distance(s.begin(), s.end()), 0); + EXPECT_THAT(std::distance(s.rbegin(), s.rend()), 0); +} + +template +void ExpectContains(const Span& s, const Source& source, size_t offset, size_t size) { + EXPECT_FALSE(s.empty()); + EXPECT_THAT(s.data(), std::data(source) + offset); + EXPECT_THAT(s.size(), size); + EXPECT_THAT(s.size_bytes(), size * sizeof(BaseType)); + EXPECT_THAT(std::distance(s.begin(), s.end()), size); + EXPECT_THAT(*s.begin(), source[offset]); + EXPECT_THAT(*(s.end() - 1), source[offset + size - 1]); + EXPECT_THAT(std::distance(s.rbegin(), s.rend()), size); + EXPECT_THAT(*s.rbegin(), source[offset + size - 1]); + EXPECT_THAT(*(s.rend() - 1), source[offset]); + EXPECT_THAT(s.front(), source[offset]); + EXPECT_THAT(s.back(), source[offset + size - 1]); + for (size_t i = 0; i < size; ++i) { + EXPECT_THAT(s[i], source[offset + i]); + } +} + +} // namespace + +TEST(SpanTest, span_ctorDefault) { + std_support::span s; + ExpectEmpty(s, nullptr); +} + +TEST(SpanTest, span0_ctorDefault) { + std_support::span s; + ExpectEmpty(s, nullptr); +} + +TEST(SpanTest, span3_ctorDefault) { + static_assert(!std::is_default_constructible_v>); +} + +TEST(SpanTest, span_ctorFirstCount) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr.data(), size); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, spanConst_ctorFirstCount) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr.data(), size); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, spanBad_ctorFirstCount) { + static_assert(!std::is_constructible_v, DerivedType*, size_t>); +} + +TEST(SpanTest, span0_ctorFirstCount) { + constexpr size_t size = 0; + std::array arr = {}; + std_support::span s(arr.data(), size); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span0Const_ctorFirstCount) { + constexpr size_t size = 0; + std::array arr = {}; + std_support::span s(arr.data(), size); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span0Bad_ctorFirstCount) { + constexpr size_t size = 0; + static_assert(!std::is_constructible_v, DerivedType*, size_t>); +} + +TEST(SpanTest, span3_ctorFirstCount) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr.data(), size); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, span3Const_ctorFirstCount) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr.data(), size); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, span3Bad_ctorFirstCount) { + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, DerivedType*, size_t>); +} + +TEST(SpanTest, span_ctorFirstLast) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr.data(), arr.data() + size); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, spanConst_ctorFirstLast) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr.data(), arr.data() + size); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, spanBad_ctorFirstLast) { + static_assert(!std::is_constructible_v, DerivedType*, DerivedType*>); +} + +TEST(SpanTest, span0_ctorFirstLast) { + constexpr size_t size = 0; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr.data(), arr.data() + size); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span0Const_ctorFirstLast) { + constexpr size_t size = 0; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr.data(), arr.data() + size); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span0Bad_ctorFirstLast) { + constexpr size_t size = 0; + static_assert(!std::is_constructible_v, DerivedType*, DerivedType*>); +} + +TEST(SpanTest, span3_ctorFirstLast) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr.data(), arr.data() + size); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, span3Const_ctorFirstLast) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr.data(), arr.data() + size); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, span3Bad_ctorFirstLast) { + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, DerivedType*, DerivedType*>); +} + +TEST(SpanTest, spanCTAD_ctorPrimArray3) { + constexpr size_t size = 3; + BaseType arr[size] = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr); + static_assert(std::is_same_v); + static_assert(decltype(s)::extent == size); +} + +TEST(SpanTest, span_ctorPrimArray3) { + constexpr size_t size = 3; + BaseType arr[size] = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, spanConst_ctorPrimArray3) { + constexpr size_t size = 3; + BaseType arr[size] = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, spanBad_ctorPrimArray3) { + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, DerivedType[size]>); +} + +TEST(SpanTest, span0_ctorPrimArray0) { + constexpr size_t size = 0; + BaseType arr[size] = {}; + std_support::span s(arr); + ExpectEmpty(s, arr); +} + +TEST(SpanTest, span0Const_ctorPrimArray0) { + constexpr size_t size = 0; + BaseType arr[size] = {}; + std_support::span s(arr); + ExpectEmpty(s, arr); +} + +TEST(SpanTest, span0Bad_ctorPrimArray0) { + constexpr size_t size = 0; + static_assert(!std::is_constructible_v, DerivedType[size]>); +} + +TEST(SpanTest, span0_ctorPrimArray5) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 0; + static_assert(!std::is_constructible_v, DerivedType[sourceSize]>); +} + +TEST(SpanTest, span3_ctorPrimArray3) { + constexpr size_t size = 3; + BaseType arr[size] = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, span3Const_ctorPrimArray3) { + constexpr size_t size = 3; + BaseType arr[size] = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, span3Bad_ctorPrimArray3) { + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, DerivedType[size]>); +} + +TEST(SpanTest, span3_ctorPrimArray0) { + constexpr size_t sourceSize = 0; + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, DerivedType[sourceSize]>); +} + +TEST(SpanTest, spanCTAD_ctorArray3) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr); + static_assert(std::is_same_v); + static_assert(decltype(s)::extent == size); +} + +TEST(SpanTest, span_ctorArray3) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, spanConst_ctorArray3) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, spanBad_ctorArray3) { + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, std::array>); +} + +TEST(SpanTest, span_ctorArray0) { + constexpr size_t sourceSize = 0; + static_assert(!std::is_constructible_v, std::array>); +} + +TEST(SpanTest, span0_ctorArray0) { + constexpr size_t size = 0; + std::array arr = {}; + std_support::span s(arr); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span0Const_ctorArray0) { + constexpr size_t size = 0; + std::array arr = {}; + std_support::span s(arr); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span0Bad_ctorArray0) { + constexpr size_t size = 0; + static_assert(!std::is_constructible_v, std::array>); +} + +TEST(SpanTest, span0_ctorArray5) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 0; + static_assert(!std::is_constructible_v, std::array>); +} + +TEST(SpanTest, span3_ctorArray3) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, span3Const_ctorArray3) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, span3Bad_ctorArray3) { + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, std::array>); +} + +TEST(SpanTest, span3_ctorArray0) { + constexpr size_t sourceSize = 0; + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, std::array>); +} + +TEST(SpanTest, spanCTAD_ctorConstArray) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr); + static_assert(std::is_same_v); + static_assert(decltype(s)::extent == size); +} + +TEST(SpanTest, spanConst_ctorConstArray3) { + constexpr size_t size = 3; + const std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, spanBad_ctorConstArray3) { + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, const std::array>); +} + +TEST(SpanTest, spanConst_ctorConstArray0) { + constexpr size_t size = 0; + const std::array arr = {}; + std_support::span s(arr); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span0_ctorConstArray0) { + constexpr size_t size = 0; + static_assert(!std::is_constructible_v, const std::array>); +} + +TEST(SpanTest, span0Const_ctorConstArray0) { + constexpr size_t size = 0; + const std::array arr = {}; + std_support::span s(arr); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span0Bad_ctorConstArray0) { + constexpr size_t size = 0; + static_assert(!std::is_constructible_v, const std::array>); +} + +TEST(SpanTest, span0_ctorConstArray5) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 0; + static_assert(!std::is_constructible_v, const std::array>); +} + +TEST(SpanTest, span3_ctorConstArray3) { + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, const std::array>); +} + +TEST(SpanTest, span3Const_ctorConstArray3) { + constexpr size_t size = 3; + const std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, span3Bad_ctorConstArray3) { + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, const std::array>); +} + +TEST(SpanTest, span3_ctorConstArray5) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, const std::array>); +} + +TEST(SpanTest, span_ctorSpan) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + const std_support::span source(arr); + std_support::span s(source); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, spanConst_ctorSpan) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + const std_support::span source(arr); + std_support::span s(source); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, spanBad_ctorSpan) { + static_assert(!std::is_constructible_v, const std_support::span>); +} + +TEST(SpanTest, span0_ctorSpan) { + constexpr size_t size = 0; + std::array arr = {}; + const std_support::span source(arr); + std_support::span s(source); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span0Const_ctorSpan) { + constexpr size_t size = 0; + std::array arr = {}; + const std_support::span source(arr); + std_support::span s(source); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span0Bad_ctorSpan) { + constexpr size_t size = 0; + static_assert(!std::is_constructible_v, const std_support::span>); +} + +TEST(SpanTest, span3_ctorSpan) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + const std_support::span source(arr); + std_support::span s(source); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, span3Const_ctorSpan) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + const std_support::span source(arr); + std_support::span s(source); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, span3Bad_ctorSpan) { + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, const std_support::span>); +} + +TEST(SpanTest, span_ctorSpan3) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + const std_support::span source(arr); + std_support::span s(source); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, spanConst_ctorSpan3) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + const std_support::span source(arr); + std_support::span s(source); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, spanBad_ctorSpan3) { + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, const std_support::span>); +} + +TEST(SpanTest, span_ctorSpan0) { + constexpr size_t size = 0; + std::array arr = {}; + const std_support::span source(arr); + std_support::span s(source); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, spanConst_ctorSpan0) { + constexpr size_t size = 0; + std::array arr = {}; + const std_support::span source(arr); + std_support::span s(source); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, spanBad_ctorSpan0) { + constexpr size_t size = 0; + static_assert(!std::is_constructible_v, const std_support::span>); +} + +TEST(SpanTest, span0_ctorSpan0) { + constexpr size_t size = 0; + std::array arr = {}; + const std_support::span source(arr); + std_support::span s(source); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span0Const_ctorSpan0) { + constexpr size_t size = 0; + std::array arr = {}; + const std_support::span source(arr); + std_support::span s(source); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span0Bad_ctorSpan0) { + constexpr size_t size = 0; + static_assert(!std::is_constructible_v, const std_support::span>); +} + +TEST(SpanTest, span3_ctorSpan0) { + constexpr size_t sourceSize = 0; + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, const std_support::span>); +} + +TEST(SpanTest, span0_ctorSpan3) { + constexpr size_t sourceSize = 3; + constexpr size_t size = 0; + static_assert(!std::is_constructible_v, const std_support::span>); +} + +TEST(SpanTest, span3_ctorSpan3) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + const std_support::span source(arr); + std_support::span s(source); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, span3Const_ctorSpan3) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + const std_support::span source(arr); + std_support::span s(source); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, span3Bad_ctorSpan3) { + constexpr size_t size = 3; + static_assert(!std::is_constructible_v, const std_support::span>); +} + +TEST(SpanTest, span_firstStatic3) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.first(); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanDeathTest, span_firstStatic7) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 7; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + EXPECT_DEATH({ source.first(); }, "Count 7 must be smaller than size 5"); +} + +TEST(SpanTest, span0_firstStatic0) { + constexpr size_t size = 0; + std::array arr = {}; + std_support::span source(arr); + auto s = source.first(); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span3_firstStatic3) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.first(); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanTest, span_firstDynamic3) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.first(size); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanDeathTest, span_firstDynamic7) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 7; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + EXPECT_DEATH({ source.first(size); }, "count 7 must be smaller than size 5"); +} + +TEST(SpanTest, span0_firstDynamic0) { + constexpr size_t size = 0; + std::array arr = {}; + std_support::span source(arr); + auto s = source.first(size); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanDeathTest, span0_firstDynamic7) { + constexpr size_t sourceSize = 0; + constexpr size_t size = 7; + std::array arr = {}; + std_support::span source(arr); + EXPECT_DEATH({ source.first(size); }, "count 7 must be smaller than size 0"); +} + +TEST(SpanTest, span5_firstDynamic3) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.first(size); + ExpectContains(s, arr, 0, size); +} + +TEST(SpanDeathTest, span5_firstDynamic7) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 7; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + EXPECT_DEATH({ source.first(size); }, "count 7 must be smaller than size 5"); +} + +TEST(SpanTest, span_lastStatic3) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 3; + constexpr size_t offset = sourceSize - size; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.last(); + ExpectContains(s, arr, offset, size); +} + +TEST(SpanTest, span0_lastStatic0) { + constexpr size_t size = 0; + std::array arr = {}; + std_support::span source(arr); + auto s = source.last(); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span5_lastStatic3) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 3; + constexpr size_t offset = sourceSize - size; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.last(); + ExpectContains(s, arr, offset, size); +} + +TEST(SpanDeathTest, span_lastStatic7) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 7; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + EXPECT_DEATH({ source.last(); }, "Count 7 must be smaller than size 5"); +} + +TEST(SpanTest, span_lastDynamic3) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 3; + constexpr size_t offset = sourceSize - size; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.last(size); + ExpectContains(s, arr, offset, size); +} + +TEST(SpanDeathTest, span_lastDynamic7) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 7; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + EXPECT_DEATH({ source.last(size); }, "count 7 must be smaller than size 5"); +} + +TEST(SpanTest, span0_lastDynamic0) { + constexpr size_t size = 0; + std::array arr = {}; + std_support::span source(arr); + auto s = source.last(size); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanDeathTest, span0_lastDynamic7) { + constexpr size_t sourceSize = 0; + constexpr size_t size = 7; + std::array arr = {}; + std_support::span source(arr); + EXPECT_DEATH({ source.last(size); }, "count 7 must be smaller than size 0"); +} + +TEST(SpanTest, span5_lastDynamic3) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 3; + constexpr size_t offset = sourceSize - size; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.last(size); + ExpectContains(s, arr, offset, size); +} + +TEST(SpanDeathTest, span5_lastDynamic7) { + constexpr size_t sourceSize = 5; + constexpr size_t size = 7; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + EXPECT_DEATH({ source.last(size); }, "count 7 must be smaller than size 5"); +} + +TEST(SpanTest, span_subspanStatic_1) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 1; + constexpr size_t size = sourceSize - offset; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.subspan(); + ExpectContains(s, arr, offset, size); +} + +TEST(SpanDeathTest, span_subspanStatic_7) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 7; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + EXPECT_DEATH({ source.subspan(); }, "Offset 7 must be smaller than size 5"); +} + +TEST(SpanTest, span0_subspanStatic_0) { + constexpr size_t size = 0; + constexpr size_t offset = 0; + std::array arr = {}; + std_support::span source(arr); + auto s = source.subspan(); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span5_subspanStatic_1) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 1; + constexpr size_t size = sourceSize - offset; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.subspan(); + ExpectContains(s, arr, offset, size); +} + +TEST(SpanTest, span_subspanStatic_1_3) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 1; + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.subspan(); + ExpectContains(s, arr, offset, size); +} + +TEST(SpanDeathTest, span_subspanStatic_7_3) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 7; + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + EXPECT_DEATH(({ source.subspan(); }), "Offset 7 must be smaller than size 5"); +} + +TEST(SpanDeathTest, span_subspanStatic_2_4) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 2; + constexpr size_t size = 4; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + EXPECT_DEATH(({ source.subspan(); }), "Count 4 must be smaller than size 5 - Offset 2"); +} + +TEST(SpanTest, span0_subspanStatic_0_0) { + constexpr size_t size = 0; + constexpr size_t offset = 0; + std::array arr = {}; + std_support::span source(arr); + auto s = source.subspan(); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanTest, span3_subspanStatic_1_3) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 1; + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.subspan(); + ExpectContains(s, arr, offset, size); +} + +TEST(SpanTest, span_subspanDynamic_1) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 1; + constexpr size_t size = sourceSize - offset; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.subspan(offset); + ExpectContains(s, arr, offset, size); +} + +TEST(SpanDeathTest, span_subspanDynamic_7) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 7; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + EXPECT_DEATH({ source.subspan(offset); }, "offset 7 must be smaller than size 5"); +} + +TEST(SpanTest, span0_subspanDynamic_0) { + constexpr size_t size = 0; + constexpr size_t offset = 0; + std::array arr = {}; + std_support::span source(arr); + auto s = source.subspan(offset); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanDeathTest, span0_subspanDynamic_7) { + constexpr size_t size = 0; + constexpr size_t offset = 7; + std::array arr = {}; + std_support::span source(arr); + EXPECT_DEATH({ source.subspan(offset); }, "offset 7 must be smaller than size 0"); +} + +TEST(SpanTest, span5_subspanDynamic_1) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 1; + constexpr size_t size = sourceSize - offset; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.subspan(offset); + ExpectContains(s, arr, offset, size); +} + +TEST(SpanDeathTest, span5_subspanDynamic_7) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 7; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + EXPECT_DEATH({ source.subspan(offset); }, "offset 7 must be smaller than size 5"); +} + +TEST(SpanTest, span_subspanDynamic_1_3) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 1; + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.subspan(offset, size); + ExpectContains(s, arr, offset, size); +} + +TEST(SpanDeathTest, span_subspanDynamic_7_3) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 7; + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + EXPECT_DEATH({ source.subspan(offset, size); }, "offset 7 must be smaller than size 5"); +} + +TEST(SpanDeathTest, span_subspanDynamic_2_4) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 2; + constexpr size_t size = 4; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + EXPECT_DEATH({ source.subspan(offset, size); }, "count 4 must be smaller than size 5 - offset 2"); +} + +TEST(SpanTest, span0_subspanDynamic_0_0) { + constexpr size_t size = 0; + constexpr size_t offset = 0; + std::array arr = {}; + std_support::span source(arr); + auto s = source.subspan(offset, size); + ExpectEmpty(s, arr.data()); +} + +TEST(SpanDeathTest, span0_subspanDynamic_7_0) { + constexpr size_t sourceSize = 0; + constexpr size_t offset = 7; + constexpr size_t size = 0; + std::array arr = {}; + std_support::span source(arr); + EXPECT_DEATH({ source.subspan(offset, size); }, "offset 7 must be smaller than size 0"); +} + +TEST(SpanDeathTest, span0_subspanDynamic_0_4) { + constexpr size_t sourceSize = 0; + constexpr size_t offset = 0; + constexpr size_t size = 4; + std::array arr = {}; + std_support::span source(arr); + EXPECT_DEATH({ source.subspan(offset, size); }, "count 4 must be smaller than size 0 - offset 0"); +} + +TEST(SpanTest, span5_subspanDynamic_1_3) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 1; + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + auto s = source.subspan(offset, size); + ExpectContains(s, arr, offset, size); +} + +TEST(SpanDeathTest, span5_subspanDynamic_7_3) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 7; + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + EXPECT_DEATH({ source.subspan(offset, size); }, "offset 7 must be smaller than size 5"); +} + +TEST(SpanDeathTest, span5_subspanDynamic_2_4) { + constexpr size_t sourceSize = 5; + constexpr size_t offset = 2; + constexpr size_t size = 4; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}, BaseType{3}, BaseType{4}}; + std_support::span source(arr); + EXPECT_DEATH({ source.subspan(offset, size); }, "count 4 must be smaller than size 5 - offset 2"); +} + +TEST(SpanDeathTest, span_front) { + std_support::span s; + EXPECT_DEATH({ s.front(); }, "Calling front on an empty span"); +} + +TEST(SpanDeathTest, span0_front) { + std_support::span s; + EXPECT_DEATH({ s.front(); }, "Calling front on an empty span"); +} + +TEST(SpanDeathTest, span_back) { + std_support::span s; + EXPECT_DEATH({ s.back(); }, "Calling back on an empty span"); +} + +TEST(SpanDeathTest, span0_back) { + std_support::span s; + EXPECT_DEATH({ s.back(); }, "Calling back on an empty span"); +} + +TEST(SpanDeathTest, span_index_5) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr); + EXPECT_DEATH({ s[5]; }, "Indexing at 5 on a span of size 3"); +} + +TEST(SpanDeathTest, span0_index_5) { + constexpr size_t size = 0; + std::array arr = {}; + std_support::span s(arr); + EXPECT_DEATH({ s[5]; }, "Indexing at 5 on a span of size 0"); +} + +TEST(SpanDeathTest, span3_index_5) { + constexpr size_t size = 3; + std::array arr = {BaseType{0}, BaseType{1}, BaseType{2}}; + std_support::span s(arr); + EXPECT_DEATH({ s[5]; }, "Indexing at 5 on a span of size 3"); +}