File: span_writer.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (154 lines) | stat: -rw-r--r-- 5,431 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_CONTAINERS_SPAN_WRITER_H_
#define BASE_CONTAINERS_SPAN_WRITER_H_

#include <optional>

#include "base/containers/span.h"
#include "base/memory/raw_span.h"
#include "base/numerics/byte_conversions.h"

namespace base {

// A Writer to write into and consume elements from the front of a span
// dynamically.
//
// SpanWriter is used to split off prefix spans from a larger span, reporting
// errors if there's not enough room left (instead of crashing, as would happen
// with span directly).
template <typename T>
class SpanWriter {
  static_assert(!std::is_const_v<T>,
                "SpanWriter needs mutable access to its buffer");

 public:
  // Construct SpanWriter that writes to `buf`.
  constexpr explicit SpanWriter(span<T> buf)
      : buf_(buf), original_size_(buf_.size()) {}

  // Returns true and writes the span `data` into the front of the inner span,
  // if there is enough room left. Otherwise, it returns false and does
  // nothing.
  constexpr bool Write(span<const T> data) {
    if (data.size() > remaining()) {
      return false;
    }
    auto [lhs, rhs] = buf_.split_at(data.size());
    lhs.copy_from(data);
    buf_ = rhs;
    return true;
  }

  // Returns true and writes `value` into the front of the inner span if there
  // is space remaining. Otherwise, it returns false and does nothing.
  template <typename V>
    requires(std::same_as<T, std::remove_cvref_t<V>>)
  bool Write(V&& value) {
    if (!remaining()) {
      return false;
    }
    buf_[0] = std::forward<V>(value);
    buf_ = buf_.last(remaining() - 1);
    return true;
  }

  // Skips over the next `n` objects, and returns a span that points to the
  // skipped objects, if there are enough objects left. Otherwise, it returns
  // nullopt and does nothing.
  constexpr std::optional<span<T>> Skip(StrictNumeric<size_t> n) {
    if (n > remaining()) {
      return std::nullopt;
    }
    auto [lhs, rhs] = buf_.split_at(n);
    buf_ = rhs;
    return lhs;
  }
  template <size_t N>
  constexpr std::optional<span<T, N>> Skip() {
    if (N > remaining()) {
      return std::nullopt;
    }
    auto [lhs, rhs] = buf_.template split_at<N>();
    buf_ = rhs;
    return lhs;
  }

  // For a SpanWriter over bytes, we can write integer values directly to those
  // bytes as a memcpy. Returns true if there was room remaining and the bytes
  // were written. The macros below implement the following methods:
  //
  // bool WriteU8BigEndian(uint8_t)
  // bool WriteU16BigEndian(uint16_t)
  // bool WriteU32BigEndian(uint32_t)
  // bool WriteU64BigEndian(uint64_t)
  // bool WriteU8LittleEndian(uint8_t)
  // bool WriteU16LittleEndian(uint16_t)
  // bool WriteU32LittleEndian(uint32_t)
  // bool WriteU64LittleEndian(uint64_t)
  // bool WriteU8NativeEndian(uint8_t)
  // bool WriteU16NativeEndian(uint16_t)
  // bool WriteU32NativeEndian(uint32_t)
  // bool WriteU64NativeEndian(uint64_t)
  // bool WriteI8BigEndian(int8_t)
  // bool WriteI16BigEndian(int16_t)
  // bool WriteI32BigEndian(int32_t)
  // bool WriteI64BigEndian(int64_t)
  // bool WriteI8LittleEndian(int8_t)
  // bool WriteI16LittleEndian(int16_t)
  // bool WriteI32LittleEndian(int32_t)
  // bool WriteI64LittleEndian(int64_t)
  // bool WriteI8NativeEndian(int8_t)
  // bool WriteI16NativeEndian(int16_t)
  // bool WriteI32NativeEndian(int32_t)
  // bool WriteI64NativeEndian(int64_t)
  //
  // Note that "native" order is almost never what you want; it only makes sense
  // for byte buffers that stay in memory and are never written to the disk or
  // network.
#define BASE_SPANWRITER_WRITE(signchar, bitsize, endian, typeprefix) \
  constexpr bool Write##signchar##bitsize##endian##Endian(           \
      typeprefix##int##bitsize##_t value)                            \
    requires(std::same_as<T, uint8_t>)                               \
  {                                                                  \
    return Write(signchar##bitsize##To##endian##Endian(value));      \
  }
#define BASE_SPANWRITER_WRITE_BOTH_SIGNS(bitsize, endian) \
  BASE_SPANWRITER_WRITE(U, bitsize, endian, u)            \
  BASE_SPANWRITER_WRITE(I, bitsize, endian, )
#define BASE_SPANWRITER_WRITE_BOTH_SIGNS_ALL_SIZES(endian) \
  BASE_SPANWRITER_WRITE_BOTH_SIGNS(8, endian)              \
  BASE_SPANWRITER_WRITE_BOTH_SIGNS(16, endian)             \
  BASE_SPANWRITER_WRITE_BOTH_SIGNS(32, endian)             \
  BASE_SPANWRITER_WRITE_BOTH_SIGNS(64, endian)

  BASE_SPANWRITER_WRITE_BOTH_SIGNS_ALL_SIZES(Big)
  BASE_SPANWRITER_WRITE_BOTH_SIGNS_ALL_SIZES(Little)
  BASE_SPANWRITER_WRITE_BOTH_SIGNS_ALL_SIZES(Native)

#undef BASE_SPANWRITER_WRITE_BOTH_SIGNS_ALL_SIZES
#undef BASE_SPANWRITER_WRITE_BOTH_SIGNS
#undef BASE_SPANWRITER_WRITE

  // Returns the remaining not-yet-written-to object count.
  constexpr size_t remaining() const { return buf_.size(); }

  // Returns the remaining not-yet-written-to objects.
  constexpr span<T> remaining_span() const { return buf_; }

  // Returns the number of objects already written (or skipped).
  constexpr size_t num_written() const { return original_size_ - buf_.size(); }

 private:
  raw_span<T> buf_;
  size_t original_size_;
};

template <class T, size_t N>
SpanWriter(span<T, N>) -> SpanWriter<T>;

}  // namespace base

#endif  // BASE_CONTAINERS_SPAN_WRITER_H_