// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved. // This file copy from https://github.com/tcbrindle/span // Modified the following points // 1. remove macros for backward compatibility with pre-C++17 standards // 2. instantiated namespace name with paddle /* This is an implementation of C++20's std::span http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/n4820.pdf */ // Copyright Tristan Brindle 2018. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file ../../LICENSE_1_0.txt or copy at // https://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include "glog/logging.h" #include "gtest/gtest.h" #include "paddle/utils/span.h" using paddle::span; // span(); TEST(default_ctor, span) { static_assert(std::is_nothrow_default_constructible>::value, ""); static_assert(std::is_nothrow_default_constructible>::value, ""); static_assert(!std::is_default_constructible>::value, ""); // dynamic size { constexpr span s{}; static_assert(s.empty(), ""); static_assert(s.data() == nullptr, ""); #ifndef _MSC_VER static_assert(s.begin() == s.end(), ""); #else CHECK(s.begin() == s.end()); #endif } // fixed size { constexpr span s{}; static_assert(s.empty(), ""); static_assert(s.data() == nullptr, ""); #ifndef _MSC_VER static_assert(s.begin() == s.end(), ""); #else CHECK(s.begin() == s.end()); #endif } } // span(pointer ptr, size_type count); TEST(pointer_length_ctor, span) { static_assert(std::is_constructible, int*, int>::value, ""); static_assert(std::is_constructible, int*, int>::value, ""); static_assert(std::is_constructible, const int*, int>::value, ""); static_assert(std::is_constructible, int*, int>::value, ""); static_assert(std::is_constructible, int*, int>::value, ""); static_assert( std::is_constructible, const int*, int>::value, ""); // dynamic size { int arr[] = {1, 2, 3}; // NOLINT span s(arr, 3); CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr); CHECK_EQ(s.begin(), std::begin(arr)); CHECK_EQ(s.end(), std::end(arr)); } // fixed size { int arr[] = {1, 2, 3}; // NOLINT span s(arr, 3); CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr); CHECK_EQ(s.begin(), std::begin(arr)); CHECK_EQ(s.end(), std::end(arr)); } } // span(pointer ptr, pointer ptr); TEST(pointer_pointer_ctor, span) { static_assert(std::is_constructible, int*, int*>::value, ""); static_assert(!std::is_constructible, float*, float*>::value, ""); static_assert(std::is_constructible, int*, int*>::value, ""); static_assert(!std::is_constructible, float*, float*>::value, ""); // dynamic size { int arr[] = {1, 2, 3}; // NOLINT span s{arr, arr + 3}; CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr); CHECK_EQ(s.begin(), std::begin(arr)); CHECK_EQ(s.end(), std::end(arr)); } // fixed size { int arr[] = {1, 2, 3}; // NOLINT span s{arr, arr + 3}; CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr); CHECK_EQ(s.begin(), std::begin(arr)); CHECK_EQ(s.end(), std::end(arr)); } } TEST(c_array_ctor, span) { using int_array_t = int[3]; // NOLINT using float_array_t = float[3]; // NOLINT static_assert(std::is_nothrow_constructible, int_array_t&>::value, ""); static_assert(!std::is_constructible, int_array_t const&>::value, ""); static_assert(!std::is_constructible, float_array_t>::value, ""); static_assert( std::is_nothrow_constructible, int_array_t&>::value, ""); static_assert( std::is_nothrow_constructible, int_array_t const&>::value, ""); static_assert(!std::is_constructible, float_array_t>::value, ""); static_assert( std::is_nothrow_constructible, int_array_t&>::value, ""); static_assert(!std::is_constructible, int_array_t const&>::value, ""); static_assert(!std::is_constructible, float_array_t&>::value, ""); static_assert( std::is_nothrow_constructible, int_array_t&>::value, ""); static_assert(std::is_nothrow_constructible, int_array_t const&>::value, ""); static_assert( !std::is_constructible, float_array_t>::value, ""); static_assert(!std::is_constructible, int_array_t&>::value, ""); static_assert( !std::is_constructible, int_array_t const&>::value, ""); static_assert(!std::is_constructible, float_array_t&>::value, ""); static_assert( !std::is_constructible, int_array_t&>::value, ""); static_assert( !std::is_constructible, int_array_t const&>::value, ""); static_assert( !std::is_constructible, float_array_t&>::value, ""); // non-const, dynamic size { int arr[] = {1, 2, 3}; // NOLINT span s{arr}; CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr); CHECK_EQ(s.begin(), std::begin(arr)); CHECK_EQ(s.end(), std::end(arr)); } // const, dynamic size { int arr[] = {1, 2, 3}; // NOLINT span s{arr}; CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr); CHECK_EQ(s.begin(), std::begin(arr)); CHECK_EQ(s.end(), std::end(arr)); } // non-const, static size { int arr[] = {1, 2, 3}; // NOLINT span s{arr}; CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr); CHECK_EQ(s.begin(), std::begin(arr)); CHECK_EQ(s.end(), std::end(arr)); } // const, dynamic size { int arr[] = {1, 2, 3}; // NOLINT span s{arr}; CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr); CHECK_EQ(s.begin(), std::begin(arr)); CHECK_EQ(s.end(), std::end(arr)); } } TEST(std_array_ctor, span) { using int_array_t = std::array; using float_array_t = std::array; using zero_array_t = std::array; static_assert(std::is_nothrow_constructible, int_array_t&>::value, ""); static_assert(!std::is_constructible, int_array_t const&>::value, ""); static_assert(!std::is_constructible, float_array_t>::value, ""); static_assert( std::is_nothrow_constructible, int_array_t&>::value, ""); static_assert( std::is_nothrow_constructible, int_array_t const&>::value, ""); static_assert( !std::is_constructible, float_array_t const&>::value, ""); static_assert( std::is_nothrow_constructible, int_array_t&>::value, ""); static_assert(!std::is_constructible, int_array_t const&>::value, ""); static_assert(!std::is_constructible, float_array_t>::value, ""); static_assert( std::is_nothrow_constructible, int_array_t&>::value, ""); static_assert(std::is_nothrow_constructible, int_array_t const&>::value, ""); static_assert( !std::is_constructible, float_array_t const&>::value, ""); static_assert(!std::is_constructible, int_array_t&>::value, ""); static_assert( !std::is_constructible, int_array_t const&>::value, ""); static_assert( !std::is_constructible, float_array_t const&>::value, ""); static_assert( !std::is_constructible, int_array_t&>::value, ""); static_assert( !std::is_constructible, int_array_t const&>::value, ""); static_assert( !std::is_constructible, float_array_t&>::value, ""); static_assert(std::is_constructible, zero_array_t&>::value, ""); static_assert(!std::is_constructible, const zero_array_t&>::value, ""); static_assert(std::is_constructible, zero_array_t&>::value, ""); static_assert( std::is_constructible, const zero_array_t&>::value, ""); static_assert(std::is_constructible, zero_array_t&>::value, ""); static_assert( !std::is_constructible, const zero_array_t&>::value, ""); static_assert(std::is_constructible, zero_array_t&>::value, ""); static_assert( std::is_constructible, const zero_array_t&>::value, ""); // non-const, dynamic size { int_array_t arr = {1, 2, 3}; span s{arr}; CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr.data()); CHECK_EQ(s.begin(), arr.data()); CHECK_EQ(s.end(), arr.data() + 3); } // const, dynamic size { int_array_t arr = {1, 2, 3}; span s{arr}; CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr.data()); CHECK_EQ(s.begin(), arr.data()); CHECK_EQ(s.end(), arr.data() + 3); } // non-const, static size { int_array_t arr = {1, 2, 3}; span s{arr}; CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr.data()); CHECK_EQ(s.begin(), arr.data()); CHECK_EQ(s.end(), arr.data() + 3); } // const, dynamic size { int_array_t arr = {1, 2, 3}; span s{arr}; CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr.data()); CHECK_EQ(s.begin(), arr.data()); CHECK_EQ(s.end(), arr.data() + 3); } } TEST(ctor_from_containers, span) { using vec_t = std::vector; using deque_t = std::deque; static_assert(std::is_constructible, vec_t&>::value, ""); static_assert(!std::is_constructible, const vec_t&>::value, ""); static_assert(!std::is_constructible, const deque_t&>::value, ""); static_assert(std::is_constructible, vec_t&>::value, ""); static_assert(std::is_constructible, const vec_t&>::value, ""); static_assert(!std::is_constructible, const deque_t&>::value, ""); static_assert(!std::is_constructible, vec_t&>::value, ""); static_assert(!std::is_constructible, const vec_t&>::value, ""); static_assert(!std::is_constructible, const deque_t&>::value, ""); static_assert(!std::is_constructible, vec_t&>::value, ""); static_assert(!std::is_constructible, const vec_t&>::value, ""); static_assert( !std::is_constructible, const deque_t&>::value, ""); // vector is not contiguous and cannot be converted to span // Regression test for https://github.com/tcbrindle/span/issues/24 static_assert(!std::is_constructible, std::vector&>::value, ""); static_assert( !std::is_constructible, const std::vector&>::value, ""); // non-const, dynamic size { vec_t arr = {1, 2, 3}; span s{arr}; CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr.data()); CHECK_EQ(s.begin(), arr.data()); CHECK_EQ(s.end(), arr.data() + 3); } // const, dynamic size { vec_t arr = {1, 2, 3}; span s{arr}; CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr.data()); CHECK_EQ(s.begin(), arr.data()); CHECK_EQ(s.end(), arr.data() + 3); } // non-const, static size { std::array arr = {1, 2, 3}; span s{arr}; CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr.data()); CHECK_EQ(s.begin(), arr.data()); CHECK_EQ(s.end(), arr.data() + 3); } // const, dynamic size { std::array arr = {1, 2, 3}; span s{arr}; CHECK_EQ(s.size(), 3UL); CHECK_EQ(s.data(), arr.data()); CHECK_EQ(s.begin(), arr.data()); CHECK_EQ(s.end(), arr.data() + 3); } } TEST(ctor_from_spans, span) { using zero_span = span; using zero_const_span = span; using big_span = span; using big_const_span = span; using dynamic_span = span; using dynamic_const_span = span; static_assert(std::is_trivially_copyable::value, ""); static_assert(std::is_trivially_move_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(std::is_nothrow_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert( std::is_nothrow_constructible::value, ""); static_assert(std::is_trivially_copyable::value, ""); static_assert(std::is_trivially_move_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert( std::is_nothrow_constructible::value, ""); static_assert( std::is_nothrow_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(std::is_trivially_copyable::value, ""); static_assert(std::is_trivially_move_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(std::is_nothrow_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(std::is_trivially_copyable::value, ""); static_assert(std::is_trivially_move_constructible::value, ""); static_assert(std::is_nothrow_constructible::value, ""); static_assert( std::is_nothrow_constructible::value, ""); static_assert( std::is_nothrow_constructible::value, ""); static_assert(std::is_nothrow_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(std::is_nothrow_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert(std::is_trivially_copyable::value, ""); static_assert(std::is_trivially_move_constructible::value, ""); static_assert(!std::is_constructible::value, ""); static_assert( std::is_nothrow_constructible::value, ""); static_assert( std::is_nothrow_constructible::value, ""); static_assert( std::is_nothrow_constructible::value, ""); static_assert( std::is_nothrow_constructible::value, ""); static_assert( std::is_nothrow_constructible::value, ""); static_assert(std::is_trivially_copyable::value, ""); static_assert(std::is_trivially_move_constructible::value, ""); constexpr zero_const_span s0{}; constexpr dynamic_const_span d{s0}; static_assert(d.empty(), ""); static_assert(d.data() == nullptr, ""); #ifndef _MSC_VER static_assert(d.begin() == d.end(), ""); #else CHECK(d.begin() == d.end()); #endif } TEST(subview, span) { // first { int arr[] = {1, 2, 3, 4, 5}; // NOLINT span s{arr}; auto f = s.first<3>(); static_assert(std::is_same>::value, ""); CHECK_EQ(f.size(), 3UL); CHECK_EQ(f.data(), arr); CHECK_EQ(f.begin(), arr); CHECK_EQ(f.end(), arr + 3); } // last { int arr[] = {1, 2, 3, 4, 5}; // NOLINT span s{arr}; auto l = s.last<3>(); static_assert(std::is_same>::value, ""); CHECK_EQ(l.size(), 3UL); CHECK_EQ(l.data(), arr + 2); CHECK_EQ(l.begin(), arr + 2); CHECK_EQ(l.end(), std::end(arr)); } // subspan { int arr[] = {1, 2, 3, 4, 5}; // NOLINT span s{arr}; auto ss = s.subspan<1, 2>(); static_assert(std::is_same>::value, ""); CHECK_EQ(ss.size(), 2UL); CHECK_EQ(ss.data(), arr + 1); CHECK_EQ(ss.begin(), arr + 1); CHECK_EQ(ss.end(), arr + 1 + 2); } // first(n) { int arr[] = {1, 2, 3, 4, 5}; // NOLINT span s{arr}; auto f = s.first(3); static_assert(std::is_same>::value, ""); CHECK_EQ(f.size(), 3UL); CHECK_EQ(f.data(), arr); CHECK_EQ(f.begin(), arr); CHECK_EQ(f.end(), arr + 3); } // last(n) { int arr[] = {1, 2, 3, 4, 5}; // NOLINT span s{arr}; auto l = s.last(3); static_assert(std::is_same>::value, ""); CHECK_EQ(l.size(), 3UL); CHECK_EQ(l.data(), arr + 2); CHECK_EQ(l.begin(), arr + 2); CHECK_EQ(l.end(), std::end(arr)); } // subspan(n) { int arr[] = {1, 2, 3, 4, 5}; // NOLINT span s{arr}; auto ss = s.subspan(1, 2); static_assert(std::is_same>::value, ""); CHECK_EQ(ss.size(), 2UL); CHECK_EQ(ss.data(), arr + 1); CHECK_EQ(ss.begin(), arr + 1); CHECK_EQ(ss.end(), arr + 1 + 2); } // TODO(tcbrindle): Test all the dynamic subspan possibilities } TEST(observers, span) { // We already use this everywhere, but whatever constexpr span empty{}; static_assert(empty.size() == 0, ""); // NOLINT static_assert(empty.empty(), ""); constexpr int arr[] = {1, 2, 3}; // NOLINT static_assert(span{arr}.size() == 3, ""); static_assert(!span{arr}.empty(), ""); } TEST(element_access, span) { constexpr int arr[] = {1, 2, 3}; // NOLINT span s{arr}; CHECK_EQ(s[0], arr[0]); CHECK_EQ(s[1], arr[1]); CHECK_EQ(s[2], arr[2]); } TEST(iterator, span) { { std::vector vec; span s{vec}; std::sort(s.begin(), s.end()); CHECK(std::is_sorted(vec.cbegin(), vec.cend())); } { const std::vector vec{1, 2, 3}; span s{vec}; CHECK(std::equal(s.rbegin(), s.rend(), vec.crbegin())); } }