blob: 14be240d26426c4f9b6205c6174020c11cee97ec [file] [log] [blame]
Atneya Nairae310802022-08-15 15:30:31 -07001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <string_view>
20#include <type_traits>
21
22#pragma push_macro("EXPLICIT_CONVERSION_GENERATE_OPERATOR")
23#undef EXPLICIT_CONVERSION_GENERATE_OPERATOR
24#define EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, op) \
25 friend constexpr bool operator op(T lhs, T rhs) { \
26 return operator op(static_cast<U>(lhs), static_cast<U>(rhs)); \
27 } \
28 friend constexpr bool operator op(T lhs, U rhs) { \
29 return operator op(static_cast<U>(lhs), rhs); \
30 } \
31 friend constexpr bool operator op(U lhs, T rhs) { \
32 return operator op(lhs, static_cast<U>(rhs)); \
33 }
34
35#pragma push_macro("EXPLICIT_CONVERSION_GENERATE_COMPARISON_OPERATORS")
36#undef EXPLICIT_CONVERSION_GENERATE_COMPARISON_OPERATORS
37// Generate comparison operator friend functions for types (appropriately
38// const/ref qualified) where T is **explicitly** convertible to U.
39#define EXPLICIT_CONVERSION_GENERATE_COMPARISON_OPERATORS(T, U) \
40 EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, ==) \
41 EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, !=) \
42 EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, <) \
43 EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, <=) \
44 EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, >) \
45 EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, >=)
46
47namespace android::mediautils {
48
49// This class a reference to a string with static storage duration
50// which is const (i.e. a string view). We expose an identical API to
51// string_view, however we do not publicly inherit to avoid potential mis-use of
52// non-virtual dtors/methods.
53//
54// We can create APIs which consume only static strings, which
55// avoids allocation/deallocation of the string locally, as well as potential
56// lifetime issues caused by consuming raw pointers (or string_views).
57// Equivalently, a string_view which is always valid, and whose underlying data
58// can never change.
59//
60// In most cases, the string_view should be initialized at compile time (and there are
61// helpers to do so below). In order to initialize a non-constexpr array,
62// the second template param must be false (i.e. opt-in).
63// Construction/usage as follows (constexpr required unless second template param is false):
64//
65// constexpr static std::array<char, 12> debugString = toStdArray("MyMethodName");
66// constexpr auto myStaticStringView = StaticStringView::create<debugString>();
67// const auto size_t length = myStaticStringView.length() // can call any string_view methods
68// globalLog(myStaticStringView, ...); // Pass to APIs consuming StaticStringViews
69//
70struct StaticStringView final : private std::string_view {
71 template <typename T>
72 struct is_const_char_array : std::false_type {};
73
74 // Use templated value helper
75 template <size_t N>
76 struct is_const_char_array<const std::array<char, N>> : std::true_type {};
77
78 template <typename T>
79 static constexpr bool is_const_char_array_v =
80 is_const_char_array<std::remove_reference_t<T>>::value;
81
82 template <auto& val, std::enable_if_t<is_const_char_array_v<decltype(val)>, bool> Check = true>
83 static constexpr StaticStringView create() {
84 if constexpr (Check) {
85 // If this static_assert fails to compile, this method was called
86 // with a non-constexpr
87 static_assert(val[0]);
88 }
89 return StaticStringView{val.data(), val.size()};
90 }
91
92 // We can copy/move assign/construct from other StaticStringViews as their validity is already
93 // ensured
94 constexpr StaticStringView(const StaticStringView& other) = default;
95 constexpr StaticStringView& operator=(const StaticStringView& other) = default;
96 constexpr StaticStringView(StaticStringView&& other) = default;
97 constexpr StaticStringView& operator=(StaticStringView&& other) = default;
98
99 // Explicitly convert to a std::string_view (this is a strict loss of
100 // information so should only be used across APIs which intend to consume
101 // any std::string_view).
102 constexpr std::string_view getStringView() const { return *this; }
103
104 // The following methods expose an identical API to std::string_view
105 using std::string_view::begin;
106 using std::string_view::cbegin;
107 using std::string_view::cend;
108 using std::string_view::crbegin;
109 using std::string_view::crend;
110 using std::string_view::end;
111 using std::string_view::rbegin;
112 using std::string_view::rend;
113 using std::string_view::operator[];
114 using std::string_view::at;
115 using std::string_view::back;
116 using std::string_view::data;
117 using std::string_view::empty;
118 using std::string_view::front;
119 using std::string_view::length;
120 using std::string_view::max_size;
121 using std::string_view::size;
122 // These modifiers are valid because the resulting view is a
123 // substring of the original static string
124 using std::string_view::remove_prefix;
125 using std::string_view::remove_suffix;
126 // Skip swap
127 using std::string_view::compare;
128 using std::string_view::copy;
129 using std::string_view::find;
130 using std::string_view::find_first_not_of;
131 using std::string_view::find_first_of;
132 using std::string_view::find_last_not_of;
133 using std::string_view::find_last_of;
134 using std::string_view::rfind;
135 using std::string_view::substr;
136#if __cplusplus >= 202202L
137 using std::string_view::ends_with;
138 using std::string_view::starts_with;
139#endif
140 using std::string_view::npos;
141
142 // Non-member friend functions to follow. Identical API to std::string_view
143 template <class CharT, class Traits>
144 friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os,
145 StaticStringView v) {
146 return os << static_cast<std::string_view&>(v);
147 }
148
149 EXPLICIT_CONVERSION_GENERATE_COMPARISON_OPERATORS(const StaticStringView&,
150 const std::string_view&)
151
152 private:
153 constexpr StaticStringView(const char* ptr, size_t sz) : std::string_view(ptr, sz){};
154
155 public:
156 // The next two functions are logically consteval (only avail in c++20).
157 // We can't use templates as params, as they would require references to
158 // static which would unnecessarily bloat executable size.
159 template <typename T, size_t N, size_t M>
160 static constexpr std::array<T, N + M> concatArray(const std::array<T, N>& a,
161 const std::array<T, M>& b) {
162 std::array<T, N + M> res{};
163 for (size_t i = 0; i < N; i++) {
164 res[i] = a[i];
165 }
166 for (size_t i = 0; i < M; i++) {
167 res[N + i] = b[i];
168 }
169 return res;
170 }
171
172 static void arrayIsNotNullTerminated();
173
174 // This method should only be called on C-style char arrays which are
175 // null-terminated. Calling this method on a char array with intermediate null
176 // characters (i.e. "hello\0" or "hel\0lo" will result in a std::array with null
177 // characters, which is most likely not intended.
178 // We attempt to detect a non-null terminated char array at link-time, but
179 // this is best effort. A consequence of this approach is that this method
180 // will fail to link for extern args, or when not inlined. Since this method
181 // is intended to be used constexpr, this is not an issue.
182 template <size_t N>
183 static constexpr std::array<char, N - 1> toStdArray(const char (&input)[N]) {
184 std::array<char, N - 1> res{};
185 for (size_t i = 0; i < N - 1; i++) {
186 res[i] = input[i];
187 }
188 // A workaround to generate a link-time error if toStdArray is not called on
189 // a null-terminated char array.
190 if (input[N - 1] != 0) arrayIsNotNullTerminated();
191 return res;
192 }
193};
194} // namespace android::mediautils
195
196// Specialization of std::hash for use with std::unordered_map
197namespace std {
198template <>
199struct hash<android::mediautils::StaticStringView> {
200 constexpr size_t operator()(const android::mediautils::StaticStringView& val) {
201 return std::hash<std::string_view>{}(val.getStringView());
202 }
203};
204} // namespace std
205
206#pragma pop_macro("EXPLICIT_CONVERSION_GENERATE_OPERATOR")
207#pragma pop_macro("EXPLICIT_CONVERSION_GENERATE_COMPARISON_OPERATORS")