File: auto_spanification_helper.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 (197 lines) | stat: -rw-r--r-- 8,866 bytes parent folder | download | duplicates (3)
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
// Copyright 2025 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_AUTO_SPANIFICATION_HELPER_H_
#define BASE_CONTAINERS_AUTO_SPANIFICATION_HELPER_H_

#include <array>

#include "base/containers/span.h"
#include "base/numerics/checked_math.h"

namespace base {

// SpanificationSizeofForStdArray was introduced temporarily in order to help
// the auto spanification tool (//tools/clang/spanify), and not meant to be
// used widely.
//
// Note that it's *not* guaranteed by the C++ standard that
//     sizeof(arr) == arr.size() * sizeof(arr[0])
// and it's possible that std::array has additional data and/or padding.
template <typename Element, size_t N>
constexpr size_t SpanificationSizeofForStdArray(const std::array<Element, N>&) {
  return sizeof(Element) * N;
}

// This helper is used to rewrite code that passes the address of a single
// variable or object member (e.g. `&my_var` or `&obj.member`) to a function
// that expects a `span` representing a single element.
//
// WARNING: This function should only be used by the auto-spanification tool.
// Do not use this helper outside of the tool.
template <typename T>
span<T, 1> SpanFromSingleElement(T& ref) {
  // This is a single element and the address is always valid as long as the
  // reference is valid.
  return UNSAFE_TODO(span<T, 1u>(&ref, 1u));
}

// Modifies the input span by removing its first element (if not empty)
// and returns the modified span.
// Used to rewrite pre-increment (++ptr).
// WARNING: This helper is intended to be used only by the auto spanification
// tool. Do not use this helper outside of the tool. Usage should usually be
// replaced with `base::span::(const_)iterator`.
template <typename T>
span<T> PreIncrementSpan(span<T>& span_ref) {
  static_assert(
      span<T>::extent == dynamic_extent,
      "PreIncrementSpan requires a dynamic-extent span (base::span<T>)");
  // An iterator that is at the end is expressed as an empty span and it shall
  // not be incremented.
  CHECK(!span_ref.empty());
  span_ref = span_ref.template subspan<1u>();
  return span_ref;
}

// Returns a copy of the input span *before* modification, and then
// modifies the input span by removing its first element (if not empty).
// Used to rewrite post-increment (ptr++).
// WARNING: This helper is intended to be used only by the auto spanification
// tool. Do not use this helper outside of the tool. Usage should usually be
// replaced with `base::span::(const_)iterator`.
template <typename T>
span<T> PostIncrementSpan(span<T>& span_ref) {
  static_assert(
      span<T>::extent == dynamic_extent,
      "PostIncrementSpan requires a dynamic-extent span (base::span<T>)");
  // An iterator that is at the end is expressed as an empty span and it shall
  // not be incremented.
  CHECK(!span_ref.empty());
  span<T> original_span = span_ref;
  span_ref = span_ref.template subspan<1u>();
  return original_span;
}

}  // namespace base

namespace base::spanification_internal {

// ToPointer is a helper function that converts either of a `T&` or a `T*` to a
// pointer `T*`.
//
// Example) Given the following two cases of spanification rewriting,
//     obj.method(arg...)  ==> MACRO(obj, arg...)
//     ptr->method(arg...) ==> MACRO(ptr, arg...)
// MACRO takes either of an optionally-const T& or T* value as the receiver
// object argument. ToPointer(obj) / ToPointer(ptr) converts them to a pointer
// type value. This helps avoiding implementing two versions of the macro.
//
// Note: This helper is intended to be used only in the following macros. Do not
// use this helper outside of them.

template <typename T>
inline const T* ToPointer(const T* value) {
  return value;
}

template <typename T>
inline T* ToPointer(T* value) {
  return value;
}

template <typename T>
inline const T* ToPointer(const T& value) {
  return &value;
}

template <typename T>
inline T* ToPointer(T& value) {
  return &value;
}

// If the value is a smart pointer type value, returns just the value.

template <typename T>
  requires requires(T t) { t.operator->(); }
inline const T& ToPointer(const T& value) {
  return value;
}

template <typename T>
  requires requires(T t) { t.operator->(); }
inline T& ToPointer(T& value) {
  return value;
}

}  // namespace base::spanification_internal

// The following helper macros are introduced temporarily in order to help the
// auto spanification tool (//tools/clang/spanify). The macros wrap third-party
// API calls which should return a base::span for safety but actually not. In
// the future, these macro calls should be replaced with new spanified APIs.
//
// The helper macros are macros because this header (in base/) cannot depend on
// non-base (especially third-party) libraries. The call sites must include
// necessary headers on their side.
//
// In the following macro definitions, a temporary lambda expression is used in
// order to not evaluate arguments multiple times. It also introduces a C++ code
// block where we can define temporary variables.

// https://source.chromium.org/chromium/chromium/src/+/main:third_party/skia/include/core/SkBitmap.h;drc=f72bd467feb15edd9323e46eab1b74ab6025bc5b;l=936
#define UNSAFE_SKBITMAP_GETADDR32(arg_self, arg_x, arg_y) \
  ([](auto&& self, int x, int y) {                        \
    uint32_t* row = self->getAddr32(x, y);                \
    ::base::CheckedNumeric<size_t> width = self->width(); \
    size_t size = (width - x).ValueOrDie();               \
    return UNSAFE_TODO(base::span<uint32_t>(row, size));  \
  }(::base::spanification_internal::ToPointer(arg_self), arg_x, arg_y))

// https://source.chromium.org/chromium/chromium/src/+/main:third_party/boringssl/src/include/openssl/pool.h;drc=c76e4f83a8c5786b463c3e55c070a21ac751b96b;l=81
#define UNSAFE_CRYPTO_BUFFER_DATA(arg_buf)                    \
  ([](const CRYPTO_BUFFER* buf) {                             \
    const uint8_t* data = CRYPTO_BUFFER_data(buf);            \
    size_t len = CRYPTO_BUFFER_len(buf);                      \
    return UNSAFE_TODO(base::span<const uint8_t>(data, len)); \
  }(arg_buf))

// https://source.chromium.org/chromium/chromium/src/+/main:third_party/harfbuzz-ng/src/src/hb-buffer.h;drc=ea6a172f84f2cbcfed803b5ae71064c7afb6b5c2;l=647
#define UNSAFE_HB_BUFFER_GET_GLYPH_INFOS(arg_buffer, arg_length)     \
  ([](hb_buffer_t* buffer, unsigned int* length) {                   \
    unsigned int len;                                                \
    hb_glyph_info_t* info = hb_buffer_get_glyph_infos(buffer, &len); \
    if (length)                                                      \
      *length = len;                                                 \
    return UNSAFE_TODO(base::span<hb_glyph_info_t>(info, len));      \
  }(arg_buffer, arg_length))

// https://source.chromium.org/chromium/chromium/src/+/main:third_party/harfbuzz-ng/src/src/hb-buffer.h;drc=c76e4f83a8c5786b463c3e55c070a21ac751b96b;l=651
#define UNSAFE_HB_BUFFER_GET_GLYPH_POSITIONS(arg_buffer, arg_length)        \
  ([](hb_buffer_t* buffer, unsigned int* length) {                          \
    unsigned int len;                                                       \
    hb_glyph_position_t* pos = hb_buffer_get_glyph_positions(buffer, &len); \
    if (length)                                                             \
      *length = len;                                                        \
    /* It's not clear whether the length is guaranteed to be 0 when !pos.   \
       Explicitly set the length to 0 just in case. */                      \
    if (!pos)                                                               \
      return UNSAFE_TODO(base::span<hb_glyph_position_t>(pos, 0u));         \
    return UNSAFE_TODO(base::span<hb_glyph_position_t>(pos, len));          \
  }(arg_buffer, arg_length))

// https://source.chromium.org/chromium/chromium/src/+/main:remoting/host/xsession_chooser_linux.cc;drc=fca90714b3949f0f4c27f26ef002fe8d33f3cb73;l=274
// https://web.mit.edu/barnowl/share/gtk-doc/html/glib/glib-Miscellaneous-Utility-Functions.html#g-get-system-data-dirs
#define UNSAFE_G_GET_SYSTEM_DATA_DIRS()                             \
  ([]() {                                                           \
    const gchar* const* dirs = g_get_system_data_dirs();            \
    size_t count = 0;                                               \
    while (UNSAFE_TODO(dirs[count]))                                \
      ++count;                                                      \
    /* It's okay to access the null-terminator at the end. */       \
    size_t size = count + 1;                                        \
    return UNSAFE_TODO(base::span<const gchar* const>(dirs, size)); \
  }())

#endif  // BASE_CONTAINERS_AUTO_SPANIFICATION_HELPER_H_