208 lines
9.0 KiB
C++
208 lines
9.0 KiB
C++
/*
|
|
* Copyright (C) 2022 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <string_view>
|
|
#include <type_traits>
|
|
|
|
#pragma push_macro("EXPLICIT_CONVERSION_GENERATE_OPERATOR")
|
|
#undef EXPLICIT_CONVERSION_GENERATE_OPERATOR
|
|
#define EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, op) \
|
|
friend constexpr bool operator op(T lhs, T rhs) { \
|
|
return operator op(static_cast<U>(lhs), static_cast<U>(rhs)); \
|
|
} \
|
|
friend constexpr bool operator op(T lhs, U rhs) { \
|
|
return operator op(static_cast<U>(lhs), rhs); \
|
|
} \
|
|
friend constexpr bool operator op(U lhs, T rhs) { \
|
|
return operator op(lhs, static_cast<U>(rhs)); \
|
|
}
|
|
|
|
#pragma push_macro("EXPLICIT_CONVERSION_GENERATE_COMPARISON_OPERATORS")
|
|
#undef EXPLICIT_CONVERSION_GENERATE_COMPARISON_OPERATORS
|
|
// Generate comparison operator friend functions for types (appropriately
|
|
// const/ref qualified) where T is **explicitly** convertible to U.
|
|
#define EXPLICIT_CONVERSION_GENERATE_COMPARISON_OPERATORS(T, U) \
|
|
EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, ==) \
|
|
EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, !=) \
|
|
EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, <) \
|
|
EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, <=) \
|
|
EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, >) \
|
|
EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, >=)
|
|
|
|
namespace android::mediautils {
|
|
|
|
// This class a reference to a string with static storage duration
|
|
// which is const (i.e. a string view). We expose an identical API to
|
|
// string_view, however we do not publicly inherit to avoid potential mis-use of
|
|
// non-virtual dtors/methods.
|
|
//
|
|
// We can create APIs which consume only static strings, which
|
|
// avoids allocation/deallocation of the string locally, as well as potential
|
|
// lifetime issues caused by consuming raw pointers (or string_views).
|
|
// Equivalently, a string_view which is always valid, and whose underlying data
|
|
// can never change.
|
|
//
|
|
// In most cases, the string_view should be initialized at compile time (and there are
|
|
// helpers to do so below). In order to initialize a non-constexpr array,
|
|
// the second template param must be false (i.e. opt-in).
|
|
// Construction/usage as follows (constexpr required unless second template param is false):
|
|
//
|
|
// constexpr static std::array<char, 12> debugString = toStdArray("MyMethodName");
|
|
// constexpr auto myStaticStringView = StaticStringView::create<debugString>();
|
|
// const auto size_t length = myStaticStringView.length() // can call any string_view methods
|
|
// globalLog(myStaticStringView, ...); // Pass to APIs consuming StaticStringViews
|
|
//
|
|
struct StaticStringView final : private std::string_view {
|
|
template <typename T>
|
|
struct is_const_char_array : std::false_type {};
|
|
|
|
// Use templated value helper
|
|
template <size_t N>
|
|
struct is_const_char_array<const std::array<char, N>> : std::true_type {};
|
|
|
|
template <typename T>
|
|
static constexpr bool is_const_char_array_v =
|
|
is_const_char_array<std::remove_reference_t<T>>::value;
|
|
|
|
template <auto& val, std::enable_if_t<is_const_char_array_v<decltype(val)>, bool> Check = true>
|
|
static constexpr StaticStringView create() {
|
|
if constexpr (Check) {
|
|
// If this static_assert fails to compile, this method was called
|
|
// with a non-constexpr
|
|
static_assert(val[0]);
|
|
}
|
|
return StaticStringView{val.data(), val.size()};
|
|
}
|
|
|
|
// We can copy/move assign/construct from other StaticStringViews as their validity is already
|
|
// ensured
|
|
constexpr StaticStringView(const StaticStringView& other) = default;
|
|
constexpr StaticStringView& operator=(const StaticStringView& other) = default;
|
|
constexpr StaticStringView(StaticStringView&& other) = default;
|
|
constexpr StaticStringView& operator=(StaticStringView&& other) = default;
|
|
|
|
// Explicitly convert to a std::string_view (this is a strict loss of
|
|
// information so should only be used across APIs which intend to consume
|
|
// any std::string_view).
|
|
constexpr std::string_view getStringView() const { return *this; }
|
|
|
|
// The following methods expose an identical API to std::string_view
|
|
using std::string_view::begin;
|
|
using std::string_view::cbegin;
|
|
using std::string_view::cend;
|
|
using std::string_view::crbegin;
|
|
using std::string_view::crend;
|
|
using std::string_view::end;
|
|
using std::string_view::rbegin;
|
|
using std::string_view::rend;
|
|
using std::string_view::operator[];
|
|
using std::string_view::at;
|
|
using std::string_view::back;
|
|
using std::string_view::data;
|
|
using std::string_view::empty;
|
|
using std::string_view::front;
|
|
using std::string_view::length;
|
|
using std::string_view::max_size;
|
|
using std::string_view::size;
|
|
// These modifiers are valid because the resulting view is a
|
|
// substring of the original static string
|
|
using std::string_view::remove_prefix;
|
|
using std::string_view::remove_suffix;
|
|
// Skip swap
|
|
using std::string_view::compare;
|
|
using std::string_view::copy;
|
|
using std::string_view::find;
|
|
using std::string_view::find_first_not_of;
|
|
using std::string_view::find_first_of;
|
|
using std::string_view::find_last_not_of;
|
|
using std::string_view::find_last_of;
|
|
using std::string_view::rfind;
|
|
using std::string_view::substr;
|
|
#if __cplusplus >= 202202L
|
|
using std::string_view::ends_with;
|
|
using std::string_view::starts_with;
|
|
#endif
|
|
using std::string_view::npos;
|
|
|
|
// Non-member friend functions to follow. Identical API to std::string_view
|
|
template <class CharT, class Traits>
|
|
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os,
|
|
StaticStringView v) {
|
|
return os << static_cast<std::string_view&>(v);
|
|
}
|
|
|
|
EXPLICIT_CONVERSION_GENERATE_COMPARISON_OPERATORS(const StaticStringView&,
|
|
const std::string_view&)
|
|
|
|
private:
|
|
constexpr StaticStringView(const char* ptr, size_t sz) : std::string_view(ptr, sz){};
|
|
|
|
public:
|
|
// The next two functions are logically consteval (only avail in c++20).
|
|
// We can't use templates as params, as they would require references to
|
|
// static which would unnecessarily bloat executable size.
|
|
template <typename T, size_t N, size_t M>
|
|
static constexpr std::array<T, N + M> concatArray(const std::array<T, N>& a,
|
|
const std::array<T, M>& b) {
|
|
std::array<T, N + M> res{};
|
|
for (size_t i = 0; i < N; i++) {
|
|
res[i] = a[i];
|
|
}
|
|
for (size_t i = 0; i < M; i++) {
|
|
res[N + i] = b[i];
|
|
}
|
|
return res;
|
|
}
|
|
|
|
static void arrayIsNotNullTerminated();
|
|
|
|
// This method should only be called on C-style char arrays which are
|
|
// null-terminated. Calling this method on a char array with intermediate null
|
|
// characters (i.e. "hello\0" or "hel\0lo" will result in a std::array with null
|
|
// characters, which is most likely not intended.
|
|
// We attempt to detect a non-null terminated char array at link-time, but
|
|
// this is best effort. A consequence of this approach is that this method
|
|
// will fail to link for extern args, or when not inlined. Since this method
|
|
// is intended to be used constexpr, this is not an issue.
|
|
template <size_t N>
|
|
static constexpr std::array<char, N - 1> toStdArray(const char (&input)[N]) {
|
|
std::array<char, N - 1> res{};
|
|
for (size_t i = 0; i < N - 1; i++) {
|
|
res[i] = input[i];
|
|
}
|
|
// A workaround to generate a link-time error if toStdArray is not called on
|
|
// a null-terminated char array.
|
|
if (input[N - 1] != 0) arrayIsNotNullTerminated();
|
|
return res;
|
|
}
|
|
};
|
|
} // namespace android::mediautils
|
|
|
|
// Specialization of std::hash for use with std::unordered_map
|
|
namespace std {
|
|
template <>
|
|
struct hash<android::mediautils::StaticStringView> {
|
|
constexpr size_t operator()(const android::mediautils::StaticStringView& val) {
|
|
return std::hash<std::string_view>{}(val.getStringView());
|
|
}
|
|
};
|
|
} // namespace std
|
|
|
|
#pragma pop_macro("EXPLICIT_CONVERSION_GENERATE_OPERATOR")
|
|
#pragma pop_macro("EXPLICIT_CONVERSION_GENERATE_COMPARISON_OPERATORS")
|