Thanks to visit codestin.com
Credit goes to chromium.googlesource.com

blob: e070b6af80a27c28374ec31b81f2ca3c4aaf4269 [file] [log] [blame]
Daniel Cheng0f38d172024-12-16 19:39:431// Copyright 2024 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 BASE_STRINGS_STRING_SLICE_H_
6#define BASE_STRINGS_STRING_SLICE_H_
7
Takuto Ikutaa1926f32025-01-07 19:06:188#include <stddef.h>
Daniel Cheng0f38d172024-12-16 19:39:439#include <stdint.h>
10
11#include <bit>
12#include <string_view>
13
14namespace base::internal {
15
16// Determines the minimum unsigned integer type needed to hold `kSize`.
17template <size_t kSize>
18struct IndexTypeForSize {
19 private:
20 static constexpr auto Helper() {
21 constexpr int kMinBits = std::bit_width(kSize);
22 if constexpr (kMinBits <= 8) {
23 return uint8_t();
24 } else if constexpr (kMinBits <= 16) {
25 return uint16_t();
26 } else if constexpr (kMinBits <= 32) {
27 return uint32_t();
28 } else {
29 return size_t();
30 }
31 }
32
33 public:
34 using Type = decltype(Helper());
35};
36
37} // namespace base::internal
38
39namespace base::subtle {
40
41// This is intended for use in tables generated by scripts and should not be
42// directly used. Consider a global constant like this:
43//
44// constexpr std::string_view kNames[] = {
45// "Alice",
46// "Bob",
47// "Eve",
48// };
49//
50// "Alice", "Bob", and "Eve" are also constants, but they are not stored inline
51// in `kNames`; `kNames[0]` points to "Alice", `kNames[1]` points to "Bob", and
52// `kNames[2]` points to "Eve". However, images can be loaded at arbitrary base
53// addresses, so the actual pointer values are unknown at build time.
54//
55// To solve this, the tooling stores `kNames` in `.data.rel.ro` and records 3
56// relocations in `.rela.dyn`. When the image is loaded, the linker applies the
57// relocations to fix up the addresses before marking the section read-only.
58//
59// Unfortunately, this has both a binary size cost (relocation entries are
60// relatively large unless RELR is in use) and a runtime cost (to apply the
61// relocations).
62//
63// StringSlice avoids relocations by only storing an offset and a length and
64// dynamically resolving to a std::string_view at runtime. Using `StringSlice`,
65// the above example might look like this instead:
66//
Daniel Cheng236c7542024-12-16 22:20:5067// constexpr char kData[] = "AliceBobEve";
68// constexpr StringSlice<sizeof(kData), kData> kNames[] = {
Daniel Cheng0f38d172024-12-16 19:39:4369// {0, 5},
70// {5, 3},
71// {8, 3},
72// };
73//
74// While this has a small runtime cost (typically a PC-relative load), modern
75// CPUs are quite good at this sort of math.
Daniel Cheng236c7542024-12-16 22:20:5076template <size_t N, const char (&kData)[N]>
Daniel Cheng0f38d172024-12-16 19:39:4377struct StringSlice {
Daniel Cheng236c7542024-12-16 22:20:5078 using IndexType = typename internal::IndexTypeForSize<N>::Type;
Daniel Cheng0f38d172024-12-16 19:39:4379
80 IndexType offset;
81 IndexType length;
82
83 friend constexpr bool operator==(StringSlice lhs, StringSlice rhs) {
84 return std::string_view(lhs) == std::string_view(rhs);
85 }
86 friend constexpr auto operator<=>(StringSlice lhs, StringSlice rhs) {
87 return std::string_view(lhs) <=> std::string_view(rhs);
88 }
89 constexpr operator std::string_view() const {
Daniel Cheng236c7542024-12-16 22:20:5090 // Note 1: using as_string_view() or span() can cause issues with constexpr
91 // evaluation limits.
92 // Note 2: Subtract 1 from kData since this is intended for use with string
93 // literals, and the terminating nul should not be included.
94 return std::string_view(kData, sizeof(kData) - 1).substr(offset, length);
Daniel Cheng0f38d172024-12-16 19:39:4395 }
96};
97
98} // namespace base::subtle
99
100#endif // BASE_STRINGS_STRING_SLICE_H_