From c1cecb25a94c075725e9d2640f6b978a8f61957b Mon Sep 17 00:00:00 2001 From: Girts Date: Fri, 8 Mar 2019 12:05:39 -0800 Subject: [PATCH] Implement Span::first and Span::last from C++20 (#274) This implements `first` and `last` methods on `Span` that mimics ones in `std::span`. --- absl/types/span.h | 34 ++++++++++++++++++++++++++++++++++ absl/types/span_test.cc | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/absl/types/span.h b/absl/types/span.h index bce18ebcb..ea1808d3b 100644 --- a/absl/types/span.h +++ b/absl/types/span.h @@ -485,6 +485,40 @@ class Span { : (base_internal::ThrowStdOutOfRange("pos > size()"), Span()); } + // Span::first() + // + // Returns a `Span` containing first `len` elements. Parameter `len` is of + // type `size_type` and thus non-negative. `len` value must be <= size(). + // + // Examples: + // + // std::vector vec = {10, 11, 12, 13}; + // absl::MakeSpan(vec).first(1); // {10} + // absl::MakeSpan(vec).first(3); // {10, 11, 12} + // absl::MakeSpan(vec).first(5); // throws std::out_of_range + constexpr Span first(size_type len) const { + return (len <= size()) + ? Span(data(), len) + : (base_internal::ThrowStdOutOfRange("len > size()"), Span()); + } + + // Span::last() + // + // Returns a `Span` containing last `len` elements. Parameter `len` is of + // type `size_type` and thus non-negative. `len` value must be <= size(). + // + // Examples: + // + // std::vector vec = {10, 11, 12, 13}; + // absl::MakeSpan(vec).last(1); // {13} + // absl::MakeSpan(vec).last(3); // {11, 12, 13} + // absl::MakeSpan(vec).last(5); // throws std::out_of_range + constexpr Span last(size_type len) const { + return (len <= size()) + ? Span(data() + size() - len, len) + : (base_internal::ThrowStdOutOfRange("len > size()"), Span()); + } + // Support for absl::Hash. template friend H AbslHashValue(H h, Span v) { diff --git a/absl/types/span_test.cc b/absl/types/span_test.cc index 294229ea0..9269f911f 100644 --- a/absl/types/span_test.cc +++ b/absl/types/span_test.cc @@ -295,6 +295,38 @@ TEST(IntSpan, Subspan) { #endif } +TEST(IntSpan, First) { + std::vector empty; + EXPECT_THAT(absl::MakeSpan(empty).first(0), SpanIs(empty)); + + auto ramp = MakeRamp(10); + EXPECT_THAT(absl::MakeSpan(ramp).first(0), SpanIs(ramp.data(), 0)); + EXPECT_THAT(absl::MakeSpan(ramp).first(10), SpanIs(ramp)); + EXPECT_THAT(absl::MakeSpan(ramp).first(3), SpanIs(ramp.data(), 3)); + +#ifdef ABSL_HAVE_EXCEPTIONS + EXPECT_THROW(absl::MakeSpan(ramp).first(11), std::out_of_range); +#else + EXPECT_DEATH_IF_SUPPORTED(absl::MakeSpan(ramp).first(11), ""); +#endif +} + +TEST(IntSpan, Last) { + std::vector empty; + EXPECT_THAT(absl::MakeSpan(empty).last(0), SpanIs(empty)); + + auto ramp = MakeRamp(10); + EXPECT_THAT(absl::MakeSpan(ramp).last(0), SpanIs(ramp.data() + 10, 0)); + EXPECT_THAT(absl::MakeSpan(ramp).last(10), SpanIs(ramp)); + EXPECT_THAT(absl::MakeSpan(ramp).last(3), SpanIs(ramp.data() + 7, 3)); + +#ifdef ABSL_HAVE_EXCEPTIONS + EXPECT_THROW(absl::MakeSpan(ramp).last(11), std::out_of_range); +#else + EXPECT_DEATH_IF_SUPPORTED(absl::MakeSpan(ramp).last(11), ""); +#endif +} + TEST(IntSpan, MakeSpanPtrLength) { std::vector empty; auto s_empty = absl::MakeSpan(empty.data(), empty.size()); @@ -769,6 +801,8 @@ TEST(ConstIntSpan, ConstexprTest) { ABSL_TEST_CONSTEXPR(span.begin()); ABSL_TEST_CONSTEXPR(span.cbegin()); ABSL_TEST_CONSTEXPR(span.subspan(0, 0)); + ABSL_TEST_CONSTEXPR(span.first(1)); + ABSL_TEST_CONSTEXPR(span.last(1)); ABSL_TEST_CONSTEXPR(span[0]); }