diff --git a/doc/core.qbk b/doc/core.qbk index 9e2c1a5..55101e3 100644 --- a/doc/core.qbk +++ b/doc/core.qbk @@ -65,6 +65,7 @@ criteria for inclusion is that the utility component be: [include quick_exit.qbk] [include ref.qbk] [include scoped_enum.qbk] +[include span.qbk] [include string_view.qbk] [include swap.qbk] [include typeinfo.qbk] diff --git a/doc/span.qbk b/doc/span.qbk new file mode 100644 index 0000000..c6205b8 --- /dev/null +++ b/doc/span.qbk @@ -0,0 +1,405 @@ +[/ +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +] + +[section:span span] + +[simplesect Authors] + +* Glen Fernandes + +[endsimplesect] + +[section Overview] + +This header provides class template `span`, which is a +view over a sequence of objects. It implements the C++20 standard library +`std::span` facility. This implementation supports C++11 and higher. + +In addition to referencing the sequence of objects, the span knows the count of +objects. There are two kinds of spans: + +* Dynamic size (`span` or `span`) +* Static size (`span`) + +Dynamic size spans have a count that can be a value known at run time. Static +size spans have a count that must be known at compile time. + +[endsect] + +[section Examples] + +The following snippet shows a function to compute a SHA1 hash whose parameters +and return type use spans. + +``` +auto sha1(boost::span input, + boost::span ouput) +{ + SHA_CTX context; + SHA1_Init(&context); + SHA1_Update(&context, input.data(), input.size()); + SHA1_Final(output.data(), &context); + return output; +} +``` + +[endsect] + +[section Reference] + +``` +namespace boost { + +constexpr std::size_t dynamic_extent = -1; + +template +class span { +public: + typedef T element_type; + typedef std::remove_cv_t value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T* iterator; + typedef const T* const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + static constexpr std::size_t extent = E; + + constexpr span() noexcept; + + explicit(E != dynamic_extent) + template + constexpr span(I* f, size_type c); + + explicit(E != dynamic_extent) + template + constexpr span(I* f, L* l); + + template + constexpr span(type_identity_t (&a)[N]); + + template + constexpr span(std::array& a) noexcept; + + template + constexpr span(const std::array& a) noexcept; + + explicit(E != dynamic_extent) + template + constexpr span(R&& r); + + explicit(E != dynamic_extent && N == dynamic_extent) + template + constexpr span(const span& s) noexcept; + + template + constexpr span first() const; + + template + constexpr span last() const; + + template + constexpr span subspan() const; + + constexpr span first(size_type c) const; + constexpr span last(size_type c) const; + + constexpr span subspan(size_type o, + size_type c = dynamic_extent) const; + + constexpr size_type size() const noexcept; + constexpr size_type size_bytes() const noexcept; + constexpr bool empty() const noexcept; + + constexpr reference operator[](size_type i) const; + constexpr reference front() const; + constexpr reference back() const; + constexpr pointer data() const noexcept; + + constexpr iterator begin() const noexcept; + constexpr iterator end() const noexcept; + constexpr reverse_iterator rbegin() const noexcept; + constexpr reverse_iterator rend() const noexcept; + constexpr const_iterator cbegin() const noexcept; + constexpr const_iterator cend() const noexcept; + constexpr const_reverse_iterator crbegin() const noexcept; + constexpr const_reverse_iterator crend() const noexcept; + + friend constexpr iterator begin(span s) noexcept { + return s.begin(); + } + + friend constexpr iterator end(span s) noexcept { + return s.end(); + } +}; + +template +span(I*, L) -> span; + +template +span(T(&)[N]) -> span; + +template +span(std::array&) -> span; + +template +span(const std::array&) -> span; + +template +span(R&&) -> span().data())> >; + +template +span +as_bytes(span s) noexcept; + +template +span +as_writable_bytes(span s) noexcept; + +} /* boost */ +``` + +[section Constructors] + +[variablelist +[[`constexpr span() noexcept;`] +[[variablelist +[[Constraints][`E == dynamic_extent || E == 0` is `true`.]] +[[Postconditions][`size() == 0 && data() == nullptr`.]]]]] +[[`explicit(E != dynamic_extent) +template +constexpr span(I* f, size_type c);`] +[[variablelist +[[Constraints] +[`is_convertible_v` is `true`.]] +[[Preconditions] +[[itemized_list +[`[f, f + c)` is a valid range.] +[If `E` is not equal to `dynamic_extent`, then `c` is equal to `E`.]]]] +[[Effects][Constructs a `span` with data `f` and size `c`.]] +[[Throws][Nothing.]]]]] +[[`explicit(E != dynamic_extent) +template +constexpr span(I* f, L* l);`] +[[variablelist +[[Constraints] +[`is_convertible_v` is `true`.]] +[[Preconditions] +[[itemized_list +[If `E` is not equal to `dynamic_extent`, then `l - f` is equal to `E`.] +[`[f, l)` is a valid range.]]]] +[[Effects][Constructs a `span` with data `f` and size `l - f`.]] +[[Throws][Nothing.]]]]] +[[`template +constexpr span(type_identity_t (&a)[N]);`] +[[variablelist +[[Constraints][`E == dynamic_extent || E == N` is `true`.]] +[[Effects][Constructs a `span` that is a view over the supplied array.]] +[[Postconditions][`size() == N && data() == &a[0]` is `true`.]]]]] +[[`template +constexpr span(std::array& a) noexcept;`] +[[variablelist +[[Constraints] +[[itemized_list +[`E == dynamic_extent || E == N` is `true`, and] +[`U(*)[]` is convertible to `T(*)[]`.]]]] +[[Effects][Constructs a `span` that is a view over the supplied array.]] +[[Postconditions][`size() == N && data() == a.data()` is `true`.]]]]] +[[`template +constexpr span(const std::array& a) noexcept;`] +[[variablelist +[[Constraints] +[[itemized_list +[`E == dynamic_extent || E == N` is `true`, and] +[`U(*)[]` is convertible to `T(*)[]`.]]]] +[[Effects][Constructs a `span` that is a view over the supplied array.]] +[[Postconditions][`size() == N && data() == a.data()` is `true`.]]]]] +[[`explicit(E != dynamic_extent) +template +constexpr span(R&& r);`] +[[variablelist +[[Constraints] +[[itemized_list +[`is_lvalue_reference_v || is_const_v` is `true`] +[`remove_cvref_t` is not a specialization of `span`,] +[`remove_cvref_t` is not a specialization of `array`,] +[`is_array_v>` is `false`,] +[`r.data()` is well-formed and +`is_convertible_v().data())>(*)[], +T(*)[]>` is `true`, and] +[`r.size()` is well-formed and +`is_convertible_v().size()), size_t>` is `true`.]]]] +[[Effects][Constructs a `span` with data `r.data()` and size `r.size()`.]] +[[Throws][What and when r.data() and r.size() throw.]]]]] +[[`explicit(E != dynamic_extent && N == dynamic_extent) +template +constexpr span(const span& s) noexcept;`] +[[variablelist +[[Constraints] +[[itemized_list +[`E == dynamic_extent || N == dynamic_extent || E == N` is `true`, and] +[`is_convertible_v` is `true`.]]]] +[[Preconditions] +[If `E` is not equal to `dynamic_extent`, then `s.size()` is equal to `E`.]] +[[Effects] +[Constructs a `span` that is a view over the range +`[s.data(), s.data() + s.size())`.]] +[[Postconditions][`size() == s.size() && data() == s.data()`.]]]]]] + +[endsect] + +[section Subviews] + +[variablelist +[[`template constexpr span first() const;`] +[[variablelist +[[Mandates][`C <= E` is `true`.]] +[[Preconditions][`C <= size()` is `true`.]] +[[Effects] +[Equivalent to `return R{data(), C};` where `R` is the return type.]]]]] +[[`template constexpr span last() const;`] +[[variablelist +[[Mandates][`C <= E` is `true`.]] +[[Preconditions][`C <= size()` is `true`.]] +[[Effects] +[Equivalent to `return R{data() + (size() - C), C};` where `R` is the return +type.]]]]] +[[`template +constexpr span subspan() const;`] +[[variablelist +[[Mandates][`O <= E && (C == dynamic_extent || C <= E - O)` is `true`.]] +[[Preconditions] +[`O <= size() && (C == dynamic_extent || C <= size() - O)` is `true`.]] +[[Effects] +[Equivalent to +`return span(data() + O, +C != dynamic_extent ? C : size() - O);`.]] +[[Remarks] +[The second template argument of the returned span type is: +`C != dynamic_extent ? C : (E != dynamic_extent ? E - O : +dynamic_extent)`]]]]] +[[`constexpr span first(size_type c) const;`] +[[variablelist +[[Preconditions][`c <= size()` is `true`.]] +[[Effects][Equivalent to: `return {data(), c};`]]]]] +[[`constexpr span last(size_type c) const;`] +[[variablelist +[[Preconditions][`c <= size()` is `true`.]] +[[Effects][Equivalent to: `return {data() + (size() - c), c};`]]]]] +[[`constexpr span subspan(size_type o, +size_type c = dynamic_extent) const;`] +[[variablelist +[[Preconditions] +[`o <= size() && (c == dynamic_extent || o + c <= size())` is `true`.]] +[[Effects] +[Equivalent to: +`return {data() + o, c == dynamic_extent ? size() - o : c};`]]]]]] + +[endsect] + +[section Observers] + +[variablelist +[[`constexpr size_type size() const noexcept;`] +[[variablelist +[[Returns][The number of elements in the span.]]]]] +[[`constexpr size_type size_bytes() const noexcept;`] +[[variablelist +[[Effects][Equivalent to: `return size() * sizeof(T);`]]]]] +[[`constexpr bool empty() const noexcept;`] +[[variablelist +[[Effects][Equivalent to: `return size() == 0;`]]]]]] + +[endsect] + +[section Element access] + +[variablelist +[[`constexpr reference operator[](size_type i) const;`] +[[variablelist +[[Preconditions][`i < size()` is `true`.]] +[[Effects][Equivalent to: `return *(data() + i);`]]]]] +[[`constexpr reference front() const;`] +[[variablelist +[[Preconditions][`empty()` is `false`.]] +[[Effects][Equivalent to: `return *data();`]]]]] +[[`constexpr reference back() const;`] +[[variablelist +[[Preconditions][`empty()` is `false`.]] +[[Effects][Equivalent to: `return *(data() + (size() - 1);`]]]]] +[[`constexpr pointer data() const noexcept;`] +[[variablelist +[[Returns][A pointer to the first element in the span.]]]]]] + +[endsect] + +[section Iterator support] + +[variablelist +[[`constexpr iterator begin() const noexcept;`] +[[variablelist +[[Returns][A constant iterator referring to the first element in the span. If `empty()`, +then it returns the same value as `cend()`.]]]]] +[[`constexpr iterator end() const noexcept;`] +[[variablelist +[[Returns][A constant iterator which is the past-the-end value.]]]]] +[[`constexpr reverse_iterator rbegin() const noexcept;`] +[[variablelist +[[Effects][Equivalent to: `return reverse_iterator(end());`]]]]] +[[`constexpr reverse_iterator rend() const noexcept;`] +[[variablelist +[[Effects][Equivalent to: `return reverse_iterator(begin());`]]]]] +[[`constexpr const_iterator cbegin() const noexcept;`] +[[variablelist +[[Returns] +[A constant iterator referring to the first element in the span. If `empty()`, +then it returns the same value as `cend()`.]]]]] +[[`constexpr const_iterator cend() const noexcept;`] +[[variablelist +[[Returns][A constant iterator which is the past-the-end value.]]]]] +[[`constexpr const_reverse_iterator crbegin() const noexcept;`] +[[variablelist +[[Effects][Equivalent to: `return const_reverse_iterator(cend());`]]]]] +[[`constexpr const_reverse_iterator crend() const noexcept;`] +[[variablelist +[[Effects] +[Equivalent to: `return const_reverse_iterator(cbegin());`]]]]]] + +[endsect] + +[section Views of object representation] + +[variablelist +[[`template +span +as_bytes(span s) noexcept;`] +[[variablelist +[[Effects] +[Equivalent to: +`return {reinterpret_cast(s.data()), s.size_bytes()};`.]]]]] +[[`template +span +as_writable_bytes(span s) noexcept;`] +[[variablelist +[[Constraints][`is_const_v` is `false`.]] +[[Effects] +[Equivalent to: `return R{reinterpret_cast(s.data()), s.size_bytes()};` +where `R` is the return type.]] +[[Returns][`false`.]]]]]] + +[endsect] + +[endsect] + +[endsect] diff --git a/include/boost/core/span.hpp b/include/boost/core/span.hpp new file mode 100644 index 0000000..bafb286 --- /dev/null +++ b/include/boost/core/span.hpp @@ -0,0 +1,403 @@ +/* +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#ifndef BOOST_CORE_SPAN_HPP +#define BOOST_CORE_SPAN_HPP + +#include +#include +#include +#include + +namespace boost { + +constexpr std::size_t dynamic_extent = -1; + +template +class span; + +namespace detail { + +template +struct span_convertible { + static constexpr bool value = std::is_convertible::value; +}; + +template +struct span_capacity { + static constexpr bool value = E == boost::dynamic_extent || E == N; +}; + +template +struct span_compatible { + static constexpr bool value = span_capacity::value && + span_convertible::value; +}; + +template +struct span_uncvref { + typedef typename std::remove_cv::type>::type type; +}; + +template +struct span_is_span { + static constexpr bool value = false; +}; + +template +struct span_is_span > { + static constexpr bool value = true; +}; + +template +struct span_is_array { + static constexpr bool value = false; +}; + +template +struct span_is_array > { + static constexpr bool value = true; +}; + +template +struct span_data { }; + +template +struct span_data().data())>::value>::type> { + typedef typename std::remove_pointer().data())>::type type; +}; + +template +struct span_has_data { + static constexpr bool value = false; +}; + +template +struct span_has_data::type, T>::value>::type> { + static constexpr bool value = true; +}; + +template +struct span_has_size { + static constexpr bool value = false; +}; + +template +struct span_has_size().size()), + std::size_t>::value>::type> { + static constexpr bool value = true; +}; + +template +struct span_is_range { + static constexpr bool value = (std::is_const::value || + std::is_lvalue_reference::value) && + !span_is_span::type>::value && + !span_is_array::type>::value && + !std::is_array::type>::value && + span_has_data::value && + span_has_size::value; +}; + +template +struct span_implicit { + static constexpr bool value = E == boost::dynamic_extent || + N != boost::dynamic_extent; +}; + +template +struct span_copyable { + static constexpr bool value = (N == boost::dynamic_extent || + span_capacity::value) && span_convertible::value; +}; + +template +struct span_sub { + static constexpr std::size_t value = E == boost::dynamic_extent ? + boost::dynamic_extent : E - O; +}; + +template +struct span_store { + constexpr span_store(T* p_, std::size_t) noexcept + : p(p_) { } + static constexpr std::size_t n = E; + T* p; +}; + +template +struct span_store { + constexpr span_store(T* p_, std::size_t n_) noexcept + : p(p_) + , n(n_) { } + T* p; + std::size_t n; +}; + +template +struct span_bytes { + static constexpr std::size_t value = E == boost::dynamic_extent ? + boost::dynamic_extent : sizeof(T) * E; +}; + +} /* detail */ + +template +class span { +public: + typedef T element_type; + typedef typename std::remove_cv::type value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T* iterator; + typedef const T* const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + static constexpr std::size_t extent = E; + + template::type = 0> + constexpr span() noexcept + : s_(0, 0) { } + + template::value, int>::type = 0> + constexpr span(I* f, size_type c) + : s_(f, c) { } + + template::value, int>::type = 0> + explicit constexpr span(I* f, size_type c) + : s_(f, c) { } + + template::value, int>::type = 0> + constexpr span(I* f, L* l) + : s_(f, l - f) { } + + template::value, int>::type = 0> + explicit constexpr span(I* f, L* l) + : s_(f, l - f) { } + + template::value, + int>::type = 0> + constexpr span(typename std::enable_if::type (&a)[N]) noexcept + : s_(a, N) { } + + template::value, + int>::type = 0> + constexpr span(std::array& a) noexcept + : s_(a.data(), N) { } + + template::value, int>::type = 0> + constexpr span(const std::array& a) noexcept + : s_(a.data(), N) { } + + template::value, int>::type = 0> + constexpr span(R&& r) noexcept(noexcept(r.data()) && noexcept(r.size())) + : s_(r.data(), r.size()) { } + + template::value, int>::type = 0> + explicit constexpr span(R&& r) noexcept(noexcept(r.data()) && + noexcept(r.size())) + : s_(r.data(), r.size()) { } + + template::value && + detail::span_copyable::value, int>::type = 0> + constexpr span(const span& s) noexcept + : s_(s.data(), s.size()) { } + + template::value && + detail::span_copyable::value, int>::type = 0> + explicit constexpr span(const span& s) noexcept + : s_(s.data(), s.size()) { } + + template + constexpr span first() const { + static_assert(C <= E, "Count <= Extent"); + return span(s_.p, C); + } + + template + constexpr span last() const { + static_assert(C <= E, "Count <= Extent"); + return span(s_.p + (s_.n - C), C); + } + + template + constexpr typename std::enable_if::value> >::type subspan() const { + static_assert(O <= E, "Offset <= Extent"); + return span::value>(s_.p + O, s_.n - O); + } + + template + constexpr typename std::enable_if >::type subspan() const { + static_assert(O <= E && C <= E - O, + "Offset <= Extent && Count <= Extent - Offset"); + return span(s_.p + O, C); + } + + constexpr span first(size_type c) const { + return span(s_.p, c); + } + + constexpr span last(size_type c) const { + return span(s_.p + (s_.n - c), c); + } + + constexpr span subspan(size_type o, + size_type c = dynamic_extent) const { + return span(s_.p + o, + c == dynamic_extent ? s_.n - o : c); + } + + constexpr size_type size() const noexcept { + return s_.n; + } + + constexpr size_type size_bytes() const noexcept { + return s_.n * sizeof(T); + } + + constexpr bool empty() const noexcept { + return s_.n == 0; + } + + constexpr reference operator[](size_type i) const { + return s_.p[i]; + } + + constexpr reference front() const { + return *s_.p; + } + + constexpr reference back() const { + return s_.p[s_.n - 1]; + } + + constexpr pointer data() const noexcept { + return s_.p; + } + + constexpr iterator begin() const noexcept { + return s_.p; + } + + constexpr iterator end() const noexcept { + return s_.p + s_.n; + } + + constexpr reverse_iterator rbegin() const noexcept { + return reverse_iterator(s_.p + s_.n); + } + + constexpr reverse_iterator rend() const noexcept { + return reverse_iterator(s_.p); + } + + constexpr const_iterator cbegin() const noexcept { + return s_.p; + } + + constexpr const_iterator cend() const noexcept { + return s_.p + s_.n; + } + + constexpr const_reverse_iterator crbegin() const noexcept { + return const_reverse_iterator(s_.p + s_.n); + } + + constexpr const_reverse_iterator crend() const noexcept { + return const_reverse_iterator(s_.p); + } + + friend constexpr iterator begin(span s) noexcept { + return s.begin(); + } + + friend constexpr iterator end(span s) noexcept { + return s.end(); + } + +private: + detail::span_store s_; +}; + +template +constexpr std::size_t span::extent; + +#ifdef __cpp_deduction_guides +template +span(I*, L) -> span; + +template +span(T(&)[N]) -> span; + +template +span(std::array&) -> span; + +template +span(const std::array&) -> span; + +template +span(R&&) -> span::type>; + +template +span(span) -> span; +#endif + +#ifdef __cpp_lib_byte +template +inline span::value> +as_bytes(span s) noexcept +{ + return span::value>(reinterpret_cast(s.data()), + s.size_bytes()); +} + +template +inline typename std::enable_if::value, + span::value> >::type +as_writable_bytes(span s) noexcept +{ + return span::value>(reinterpret_cast(s.data()), s.size_bytes()); +} +#endif + +} /* boost */ + +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 7a1912c..6ebefb6 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -8,6 +8,7 @@ import modules ; import testing ; +import ../../config/checks/config : requires ; # quick test (for CI) run quick.cpp ; @@ -269,5 +270,12 @@ run sv_lt_test.cpp ; run sv_stream_insert_test.cpp ; run sv_conversion_test.cpp ; +run span_test.cpp : : : [ requires cxx11_constexpr cxx11_decltype ] ; +run span_types_test.cpp : : : [ requires cxx11_constexpr cxx11_decltype ] ; +run span_constructible_test.cpp : : : [ requires cxx11_constexpr cxx11_decltype ] ; +run span_deduction_guide_test.cpp : : : [ requires cpp_deduction_guides ] ; +run as_bytes_test.cpp : : : [ requires cpp_lib_byte ] ; +run as_writable_bytes_test.cpp : : : [ requires cpp_lib_byte ] ; + use-project /boost/core/swap : ./swap ; build-project ./swap ; diff --git a/test/as_bytes_test.cpp b/test/as_bytes_test.cpp new file mode 100644 index 0000000..e99ef5d --- /dev/null +++ b/test/as_bytes_test.cpp @@ -0,0 +1,34 @@ +/* +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#include +#include + +void test_dynamic() +{ + int a[4]; + boost::span s = + boost::as_bytes(boost::span(&a[0], 4)); + BOOST_TEST_EQ(s.data(), reinterpret_cast(&a[0])); + BOOST_TEST_EQ(s.size(), sizeof(int) * 4); +} + +void test_static() +{ + int a[4]; + boost::span s = + boost::as_bytes(boost::span(&a[0], 4)); + BOOST_TEST_EQ(s.data(), reinterpret_cast(&a[0])); + BOOST_TEST_EQ(s.size(), sizeof(int) * 4); +} + +int main() +{ + test_dynamic(); + test_static(); + return boost::report_errors(); +} diff --git a/test/as_writable_bytes_test.cpp b/test/as_writable_bytes_test.cpp new file mode 100644 index 0000000..47914d8 --- /dev/null +++ b/test/as_writable_bytes_test.cpp @@ -0,0 +1,34 @@ +/* +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#include +#include + +void test_dynamic() +{ + int a[4]; + boost::span s = + boost::as_writable_bytes(boost::span(&a[0], 4)); + BOOST_TEST_EQ(s.data(), reinterpret_cast(&a[0])); + BOOST_TEST_EQ(s.size(), sizeof(int) * 4); +} + +void test_static() +{ + int a[4]; + boost::span s = + boost::as_writable_bytes(boost::span(&a[0], 4)); + BOOST_TEST_EQ(s.data(), reinterpret_cast(&a[0])); + BOOST_TEST_EQ(s.size(), sizeof(int) * 4); +} + +int main() +{ + test_dynamic(); + test_static(); + return boost::report_errors(); +} diff --git a/test/span_constructible_test.cpp b/test/span_constructible_test.cpp new file mode 100644 index 0000000..857eada --- /dev/null +++ b/test/span_constructible_test.cpp @@ -0,0 +1,192 @@ +/* +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#include +#include + +template +struct range { + T* data() { + return 0; + } + + const T* data() const { + return 0; + } + + std::size_t size() const { + return 0; + } +}; + +struct base { }; + +struct derived + : base { }; + +void test_default() +{ + BOOST_TEST_TRAIT_TRUE((std::is_default_constructible< + boost::span >)); + BOOST_TEST_TRAIT_TRUE((std::is_default_constructible< + boost::span >)); + BOOST_TEST_TRAIT_FALSE((std::is_default_constructible< + boost::span >)); +} + +void test_data_size() +{ + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + int*, std::size_t>)); + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + int*, std::size_t>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + int, std::size_t>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + const int*, std::size_t>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + derived*, std::size_t>)); +} + +void test_first_last() +{ + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + int*, int*>)); + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + int*, const int*>)); + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + int*, int*>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + int, int*>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + const int*, int*>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + derived*, derived*>)); +} + +void test_array() +{ + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + int(&)[4]>)); + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + int(&)[4]>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + int(&)[4]>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + int(&)[2]>)); +} + +void test_std_array() +{ + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + std::array&>)); + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + std::array&>)); + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + std::array&>)); + BOOST_TEST_TRAIT_TRUE((std::is_constructible, std::array&>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + std::array&>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + std::array&>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + std::array&>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + std::array&>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + std::array&>)); +} + +void test_const_std_array() +{ + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + const std::array >)); + BOOST_TEST_TRAIT_TRUE((std::is_constructible, const std::array >)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + const std::array >)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, const std::array >)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, const std::array >)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + const std::array >)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, const std::array >)); +} + +void test_range() +{ + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + range&>)); + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + range&>)); + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + range >)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + int*>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + range >)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + const range&>)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + range&>)); +} + +void test_span() +{ + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + boost::span >)); + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + boost::span >)); + BOOST_TEST_TRAIT_TRUE((std::is_constructible, + boost::span >)); + BOOST_TEST_TRAIT_TRUE((std::is_constructible, boost::span >)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + boost::span >)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + boost::span >)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + boost::span >)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + boost::span >)); + BOOST_TEST_TRAIT_FALSE((std::is_constructible, + boost::span >)); +} + +void test_copy() +{ + BOOST_TEST_TRAIT_TRUE((std::is_copy_constructible< + boost::span >)); + BOOST_TEST_TRAIT_TRUE((std::is_copy_constructible< + boost::span >)); +} + +void test_assign() +{ + BOOST_TEST_TRAIT_TRUE((std::is_copy_assignable< + boost::span >)); + BOOST_TEST_TRAIT_TRUE((std::is_copy_assignable< + boost::span >)); +} + +int main() +{ + test_default(); + test_data_size(); + test_first_last(); + test_array(); + test_std_array(); + test_const_std_array(); + test_range(); + test_span(); + test_copy(); + test_assign(); + return boost::report_errors(); +} diff --git a/test/span_deduction_guide_test.cpp b/test/span_deduction_guide_test.cpp new file mode 100644 index 0000000..c627ba8 --- /dev/null +++ b/test/span_deduction_guide_test.cpp @@ -0,0 +1,109 @@ +/* +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#include +#include + +template +class range { +public: + T* data() { + return &v_[0]; + } + + std::size_t size() const { + return 4; + } + +private: + T v_[4]; +}; + +void test_data_size() +{ + int a[4]; + boost::span s(&a[0], 4); + BOOST_TEST_EQ(s.extent, boost::dynamic_extent); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 4); +} + +void test_first_last() +{ + int a[4]; + boost::span s(&a[0], &a[4]); + BOOST_TEST_EQ(s.extent, boost::dynamic_extent); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 4); +} + +void test_array() +{ + int a[4]; + boost::span s(a); + BOOST_TEST_EQ(s.extent, 4); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 4); +} + +void test_std_array() +{ + std::array a; + boost::span s(a); + BOOST_TEST_EQ(s.extent, 4); + BOOST_TEST_EQ(s.data(), a.data()); + BOOST_TEST_EQ(s.size(), a.size()); +} + +void test_const_std_array() +{ + const std::array a = std::array(); + boost::span s(a); + BOOST_TEST_EQ(s.extent, 4); + BOOST_TEST_EQ(s.data(), a.data()); + BOOST_TEST_EQ(s.size(), a.size()); +} + +void test_range() +{ + range c; + boost::span s(c); + BOOST_TEST_EQ(s.extent, boost::dynamic_extent); + BOOST_TEST_EQ(s.data(), c.data()); + BOOST_TEST_EQ(s.size(), c.size()); +} + +void test_span_dynamic() +{ + int a[4]; + boost::span s(boost::span(&a[0], 4)); + BOOST_TEST_EQ(s.extent, boost::dynamic_extent); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 4); +} + +void test_span_static() +{ + int a[4]; + boost::span s(boost::span(&a[0], 4)); + BOOST_TEST_EQ(s.extent, 4); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 4); +} + +int main() +{ + test_data_size(); + test_first_last(); + test_array(); + test_std_array(); + test_const_std_array(); + test_range(); + test_span_dynamic(); + test_span_static(); + return boost::report_errors(); +} diff --git a/test/span_test.cpp b/test/span_test.cpp new file mode 100644 index 0000000..5ef1d22 --- /dev/null +++ b/test/span_test.cpp @@ -0,0 +1,425 @@ +/* +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#include +#include + +template +class range { +public: + T* data() { + return &v_[0]; + } + + std::size_t size() const { + return 4; + } + +private: + T v_[4]; +}; + +void test_extent() +{ + BOOST_TEST_EQ(boost::span::extent, + boost::dynamic_extent); + BOOST_TEST_EQ((boost::span::extent), 2); +} + +void test_default_construct_dynamic() +{ + boost::span s; + BOOST_TEST_EQ(s.data(), static_cast(0)); + BOOST_TEST_EQ(s.size(), 0); +} + +void test_default_construct_static() +{ + boost::span s; + BOOST_TEST_EQ(s.data(), static_cast(0)); + BOOST_TEST_EQ(s.size(), 0); +} + +void test_construct_data_size() +{ + int a[4]; + boost::span s(&a[0], 4); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 4); +} + +void test_construct_first_last() +{ + int a[4]; + boost::span s(&a[0], &a[4]); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 4); +} + +void test_construct_array_dynamic() +{ + int a[4]; + boost::span s(a); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 4); +} + +void test_construct_array_static() +{ + int a[4]; + boost::span s(a); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 4); +} + +void test_construct_std_array_dynamic() +{ + std::array a; + boost::span s(a); + BOOST_TEST_EQ(s.data(), a.data()); + BOOST_TEST_EQ(s.size(), a.size()); +} + +void test_construct_std_array_static() +{ + std::array a; + boost::span s(a); + BOOST_TEST_EQ(s.data(), a.data()); + BOOST_TEST_EQ(s.size(), a.size()); +} + +void test_construct_const_std_array_dynamic() +{ + const std::array a = std::array(); + boost::span s(a); + BOOST_TEST_EQ(s.data(), a.data()); + BOOST_TEST_EQ(s.size(), a.size()); +} + +void test_construct_const_std_array_static() +{ + const std::array a = std::array(); + boost::span s(a); + BOOST_TEST_EQ(s.data(), a.data()); + BOOST_TEST_EQ(s.size(), a.size()); +} + +void test_construct_range() +{ + range c; + boost::span s(c); + BOOST_TEST_EQ(s.data(), c.data()); + BOOST_TEST_EQ(s.size(), c.size()); +} + +void test_construct_span_dynamic() +{ + int a[4]; + boost::span s(boost::span(&a[0], 4)); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 4); +} + +void test_construct_span_dynamic_static() +{ + int a[4]; + boost::span s(boost::span(&a[0], 4)); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 4); +} + +void test_construct_span_static() +{ + int a[4]; + boost::span s(boost::span(&a[0], 4)); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 4); +} + +void test_construct_span_static_dynamic() +{ + int a[4]; + boost::span s(boost::span(&a[0], 4)); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 4); +} + +void test_copy_dynamic() +{ + int a[4]; + boost::span s1(&a[0], 4); + boost::span s2(s1); + BOOST_TEST_EQ(s2.data(), &a[0]); + BOOST_TEST_EQ(s2.size(), 4); +} + +void test_copy_static() +{ + int a[4]; + boost::span s1(&a[0], 4); + boost::span s2(s1); + BOOST_TEST_EQ(s2.data(), &a[0]); + BOOST_TEST_EQ(s2.size(), 4); +} + +void test_assign_dynamic() +{ + boost::span s; + int a[4]; + s = boost::span(&a[0], 4); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 4); +} + +void test_assign_static() +{ + int a1[4]; + boost::span s(&a1[0], 4); + int a2[4]; + s = boost::span(&a2[0], 4); + BOOST_TEST_EQ(s.data(), &a2[0]); + BOOST_TEST_EQ(s.size(), 4); +} + +void test_first() +{ + int a[4]; + boost::span s = boost::span(&a[0], + 4).first<2>(); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 2); +} + +void test_last() +{ + int a[4]; + boost::span s = boost::span(&a[0], 4).last<2>(); + BOOST_TEST_EQ(s.data(), &a[2]); + BOOST_TEST_EQ(s.size(), 2); +} + +void test_subspan_dynamic() +{ + int a[4]; + boost::span s = boost::span(&a[0], 4).subspan<2>(); + BOOST_TEST_EQ(s.data(), &a[2]); + BOOST_TEST_EQ(s.size(), 2); +} + +void test_subspan_static() +{ + int a[4]; + boost::span s = boost::span(&a[0], + 4).subspan<2>(); + BOOST_TEST_EQ(s.data(), &a[2]); + BOOST_TEST_EQ(s.size(), 2); +} + +void test_subspan() +{ + int a[4]; + boost::span s = boost::span(&a[0], + 4).subspan<2, 1>(); + BOOST_TEST_EQ(s.data(), &a[2]); + BOOST_TEST_EQ(s.size(), 1); +} + +void test_first_size() +{ + int a[4]; + boost::span s = boost::span(&a[0], 4).first(2); + BOOST_TEST_EQ(s.data(), &a[0]); + BOOST_TEST_EQ(s.size(), 2); +} + +void test_last_size() +{ + int a[4]; + boost::span s = boost::span(&a[0], 4).last(2); + BOOST_TEST_EQ(s.data(), &a[2]); + BOOST_TEST_EQ(s.size(), 2); +} + +void test_subspan_range() +{ + int a[4]; + boost::span s = boost::span(&a[0], 4).subspan(2); + BOOST_TEST_EQ(s.data(), &a[2]); + BOOST_TEST_EQ(s.size(), 2); +} + +void test_subspan_range_count() +{ + int a[4]; + boost::span s = boost::span(&a[0], + 4).subspan(2, 1); + BOOST_TEST_EQ(s.data(), &a[2]); + BOOST_TEST_EQ(s.size(), 1); +} + +void test_size() +{ + int a[4]; + BOOST_TEST_EQ((boost::span(&a[0], 4).size()), 4); +} + +void test_size_bytes() +{ + int a[4]; + BOOST_TEST_EQ((boost::span(&a[0], 4).size_bytes()), + 4 * sizeof(int)); +} + +void test_empty_dynamic() +{ + int a[4]; + BOOST_TEST(boost::span().empty()); + BOOST_TEST_NOT((boost::span(&a[0], 4).empty())); +} + +void test_empty_static() +{ + int a[4]; + BOOST_TEST((boost::span().empty())); + BOOST_TEST_NOT((boost::span(&a[0], 4).empty())); +} + +void test_index() +{ + int a[4] = { 1, 2, 3, 4 }; + BOOST_TEST_EQ((boost::span(&a[0], 4)[2]), 3); +} + +void test_front() +{ + int a[4] = { 1, 2, 3, 4 }; + BOOST_TEST_EQ((boost::span(&a[0], 4).front()), 1); +} + +void test_back() +{ + int a[4] = { 1, 2, 3, 4 }; + BOOST_TEST_EQ((boost::span(&a[0], 4).back()), 4); +} + +void test_data() +{ + int a[4]; + BOOST_TEST_EQ((boost::span(&a[0], 4).data()), &a[0]); +} + +void test_begin() +{ + int a[4]; + BOOST_TEST_EQ((boost::span(&a[0], 4).begin()), &a[0]); +} + +void test_end() +{ + int a[4]; + BOOST_TEST_EQ((boost::span(&a[0], 4).end()), &a[4]); +} + +void test_rbegin() +{ + int a[4]; + BOOST_TEST_EQ((boost::span(&a[0], 4).rbegin().base()), &a[4]); +} + +void test_rend() +{ + int a[4]; + BOOST_TEST_EQ((boost::span(&a[0], 4).rend().base()), &a[0]); +} + +void test_cbegin() +{ + int a[4]; + BOOST_TEST_EQ((boost::span(&a[0], 4).cbegin()), &a[0]); +} + +void test_cend() +{ + int a[4]; + BOOST_TEST_EQ((boost::span(&a[0], 4).cend()), &a[4]); +} + +void test_crbegin() +{ + int a[4]; + BOOST_TEST_EQ((boost::span(&a[0], 4).crbegin().base()), &a[4]); +} + +void test_crend() +{ + int a[4]; + BOOST_TEST_EQ((boost::span(&a[0], 4).crend().base()), &a[0]); +} + +void test_begin_span() +{ + int a[4]; + BOOST_TEST_EQ((begin(boost::span(&a[0], 4))), &a[0]); +} + +void test_end_span() +{ + int a[4]; + BOOST_TEST_EQ((end(boost::span(&a[0], 4))), &a[4]); +} + +int main() +{ + test_extent(); + test_default_construct_dynamic(); + test_default_construct_static(); + test_construct_data_size(); + test_construct_first_last(); + test_construct_array_dynamic(); + test_construct_array_static(); + test_construct_std_array_dynamic(); + test_construct_std_array_static(); + test_construct_const_std_array_dynamic(); + test_construct_const_std_array_static(); + test_construct_range(); + test_construct_span_dynamic(); + test_construct_span_dynamic_static(); + test_construct_span_static(); + test_construct_span_static_dynamic(); + test_copy_dynamic(); + test_copy_static(); + test_assign_dynamic(); + test_assign_static(); + test_first(); + test_last(); + test_subspan_dynamic(); + test_subspan_static(); + test_subspan(); + test_first_size(); + test_last_size(); + test_subspan_range(); + test_subspan_range_count(); + test_size(); + test_size_bytes(); + test_empty_dynamic(); + test_empty_static(); + test_index(); + test_front(); + test_back(); + test_data(); + test_begin(); + test_end(); + test_rbegin(); + test_rend(); + test_cbegin(); + test_cend(); + test_crbegin(); + test_crend(); + test_begin_span(); + test_end_span(); + return boost::report_errors(); +} diff --git a/test/span_types_test.cpp b/test/span_types_test.cpp new file mode 100644 index 0000000..56c7413 --- /dev/null +++ b/test/span_types_test.cpp @@ -0,0 +1,128 @@ +/* +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#include +#include + +void test_element_type() +{ + BOOST_TEST_TRAIT_SAME(int, + boost::span::element_type); + BOOST_TEST_TRAIT_SAME(char, + boost::span::element_type); +} + +void test_value_type() +{ + BOOST_TEST_TRAIT_SAME(char, + boost::span::value_type); + BOOST_TEST_TRAIT_SAME(int, + boost::span::value_type); + BOOST_TEST_TRAIT_SAME(int, + boost::span::value_type); + BOOST_TEST_TRAIT_SAME(int, + boost::span::value_type); + BOOST_TEST_TRAIT_SAME(int, + boost::span::value_type); +} + +void test_size_type() +{ + BOOST_TEST_TRAIT_SAME(std::size_t, + boost::span::size_type); + BOOST_TEST_TRAIT_SAME(std::size_t, + boost::span::size_type); +} + +void test_difference_type() +{ + BOOST_TEST_TRAIT_SAME(std::ptrdiff_t, + boost::span::difference_type); + BOOST_TEST_TRAIT_SAME(std::ptrdiff_t, + boost::span::difference_type); +} + +void test_pointer() +{ + BOOST_TEST_TRAIT_SAME(char*, + boost::span::pointer); + BOOST_TEST_TRAIT_SAME(int*, + boost::span::pointer); +} + +void test_const_pointer() +{ + BOOST_TEST_TRAIT_SAME(const char*, + boost::span::const_pointer); + BOOST_TEST_TRAIT_SAME(const int*, + boost::span::const_pointer); +} + +void test_reference() +{ + BOOST_TEST_TRAIT_SAME(char&, + boost::span::reference); + BOOST_TEST_TRAIT_SAME(int&, + boost::span::reference); +} + +void test_const_reference() +{ + BOOST_TEST_TRAIT_SAME(const char&, + boost::span::const_reference); + BOOST_TEST_TRAIT_SAME(const int&, + boost::span::const_reference); +} + +void test_iterator() +{ + BOOST_TEST_TRAIT_SAME(char*, + boost::span::iterator); + BOOST_TEST_TRAIT_SAME(int*, + boost::span::iterator); +} + +void test_const_iterator() +{ + BOOST_TEST_TRAIT_SAME(const char*, + boost::span::const_iterator); + BOOST_TEST_TRAIT_SAME(const int*, + boost::span::const_iterator); +} + +void test_reverse_iterator() +{ + BOOST_TEST_TRAIT_SAME(std::reverse_iterator, + boost::span::reverse_iterator); + BOOST_TEST_TRAIT_SAME(std::reverse_iterator, + boost::span::reverse_iterator); +} + +void test_const_reverse_iterator() +{ + BOOST_TEST_TRAIT_SAME(std::reverse_iterator, + boost::span::const_reverse_iterator); + BOOST_TEST_TRAIT_SAME(std::reverse_iterator, + boost::span::const_reverse_iterator); +} + +int main() +{ + test_element_type(); + test_value_type(); + test_size_type(); + test_difference_type(); + test_pointer(); + test_const_pointer(); + test_reference(); + test_const_reference(); + test_iterator(); + test_const_iterator(); + test_reverse_iterator(); + test_const_reverse_iterator(); + return boost::report_errors(); +}