blob: 11edcf5176bdaa4be8bb6b38e224fd8acd07f307 [file] [log] [blame]
mark a. foltzcf5b8ca2023-02-07 14:44:54 -08001// Copyright 2023 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef PLATFORM_BASE_SPAN_H_
6#define PLATFORM_BASE_SPAN_H_
7
8#include <stddef.h>
9#include <stdint.h>
10
11#include <cassert>
12#include <type_traits>
13#include <vector>
14
15namespace openscreen {
16
17template <typename T>
18class Span;
19
20// In Open Screen code, use these aliases for the most common types of Spans.
21// These can be converted to use std::span once the library supports C++20.
22using ByteView = Span<const uint8_t>;
23using ByteBuffer = Span<uint8_t>;
24
25namespace internal {
26
27template <typename From, typename To>
28using EnableIfConvertible = std::enable_if_t<
29 std::is_convertible<From (*)[], To (*)[]>::value>; // NOLINT
30
31} // namespace internal
32
33// Contains a pointer and length to a span of contiguous data.
34//
35// The API is a slimmed-down version of a C++20 std::span<T> and is intended to
36// be forwards-compatible with very slight modifications. We don't intend to
37// add support for static extents.
38//
39// NOTES:
40// - Although other span implementations allow passing zero to last(), we do
41// not, as the behavior is undefined. Callers should explicitly create an
42// empty Span instead.
43//
44// - operator== is not implemented to align with std::span. For more
45// discussion, this blog post has considerations when implementing operators
46// on types that don't own the data they depend upon:
47// https://abseil.io/blog/20180531-regular-types
48//
49// - Unit tests that want to compare the bytes behind two ByteViews can use
50// ExpectByteViewsHaveSameBytes().
51template <typename T>
52class Span {
53 public:
54 constexpr Span() noexcept = default;
55 constexpr Span(const Span&) noexcept = default;
56 Span(Span&& other) noexcept = default;
57 constexpr Span& operator=(const Span&) noexcept = default;
58 Span& operator=(Span&& other) noexcept = default;
59
60 constexpr Span(T* data, size_t count) : data_(data), count_(count) {}
61
62 template <typename U, typename = internal::EnableIfConvertible<U, T>>
63 Span(std::vector<U>& v) : data_(v.data()), count_(v.size()) {} // NOLINT
64
65 template <typename U, typename = internal::EnableIfConvertible<U, T>>
66 constexpr Span(const Span<U>& other) noexcept
67 : data_(other.data()), count_(other.size()) {} // NOLINT
68
69 template <typename U, typename = internal::EnableIfConvertible<U, T>>
70 constexpr Span& operator=(const Span<U>& other) noexcept {
71 data_ = other.data();
72 count_ = other.size();
73 return *this;
74 }
75
76 ~Span() = default;
77
78 constexpr T* data() const noexcept { return data_; }
79
80 constexpr T& operator[](size_t idx) const {
81 assert(idx < count_);
82 return *(data_ + idx);
83 }
84
85 constexpr size_t size() const { return count_; }
86
87 [[nodiscard]] constexpr bool empty() const { return count_ == 0; }
88
89 constexpr Span first(size_t count) const {
90 assert(count <= count_);
91 return Span(data_, count);
92 }
93
94 constexpr Span last(size_t count) const {
95 assert(count <= count_);
96 assert(count != 0);
97 return Span(data_ + (count_ - count), count);
98 }
99
100 constexpr T* begin() const noexcept { return data_; }
101 constexpr T* end() const noexcept { return data_ + count_; }
102 constexpr const T* cbegin() const noexcept { return data_; }
103 constexpr const T* cend() const noexcept { return data_ + count_; }
104
105 void remove_prefix(size_t count) noexcept {
106 assert(count_ >= count);
107 data_ += count;
108 count_ -= count;
109 }
110
111 void remove_suffix(size_t count) noexcept {
112 assert(count_ >= count);
113 count_ -= count;
114 }
115
116 constexpr Span subspan(size_t offset, size_t count) const {
117 assert(offset + count < count_);
118 return Span(data_ + offset, count);
119 }
120
121 private:
122 T* data_{nullptr};
123 size_t count_{0};
124};
125
126} // namespace openscreen
127
128#endif // PLATFORM_BASE_SPAN_H_