Files
mongo/src/mongo/base/string_data.h
Billy Donahue ea26ea28ac SERVER-105843 remove StringData.toString (#36937)
GitOrigin-RevId: e3d03a3ab4e1f6158a425e70ee4c4fc63af1313e
2025-06-09 16:46:48 +00:00

406 lines
14 KiB
C++

/**
* Copyright (C) 2018-present MongoDB, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the Server Side Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#pragma once
#include "mongo/platform/compiler.h"
#include "mongo/stdx/type_traits.h"
#include "mongo/util/assert_util_core.h"
#include "mongo/util/ctype.h"
#include "mongo/util/debug_util.h"
#include <algorithm>
#include <concepts>
#include <cstring>
#include <functional>
#include <iosfwd>
#include <limits>
#include <stdexcept>
#include <string>
#include <string_view> // NOLINT
#include <type_traits>
#include <absl/hash/hash.h>
#include <fmt/format.h>
namespace mongo {
/**
* A StringData object refers to an array of `char` without owning it.
* The most common usage is as a function argument.
*
* Implements the API of `std::string_view`, and is implemented
* by forwarding member functions to the internal `string_view` member.
* Ultimately this class will be removed and we'll just use `std::string_view`
* directly, so we must restrict it to the feature set of `std::string_view`
* supported by all supported platforms. They are not all the same.
*
* The iterator is not always a raw pointer. On Windows, it is a class,
* which enables useful integrity checks in debug builds.
*
* The string data to which StringData refers must outlive it.
*
* StringData is not null-terminated.
*
* StringData should almost always be passed by value.
*
* See https://en.cppreference.com/w/cpp/string/basic_string_view.
*/
class MONGO_GSL_POINTER StringData {
public:
using value_type = std::string_view::value_type;
using const_pointer = std::string_view::const_pointer;
using pointer = std::string_view::pointer;
using const_reference = std::string_view::const_reference;
using reference = std::string_view::reference;
using const_iterator = std::string_view::const_iterator;
using iterator = std::string_view::iterator;
using const_reverse_iterator = std::string_view::const_reverse_iterator;
using reverse_iterator = std::string_view::reverse_iterator;
using size_type = std::string_view::size_type;
using difference_type = std::string_view::difference_type;
static constexpr inline size_type npos = std::string_view::npos;
constexpr StringData() = default;
StringData(std::nullptr_t) = delete; // C++23, but harmless
/**
* Used where string length is not known in advance.
* 'c' must be null or point to a null-terminated string.
*/
constexpr StringData(const char* c)
: StringData{c ? std::string_view{c} : std::string_view{}} {}
StringData(const std::string& s) : StringData{std::string_view{s}} {}
/**
* Constructs a StringData with an explicit length. 'c' must
* either be nullptr (in which case len must be zero), or be a
* pointer into a character array. The StringData will refer to
* the first 'len' characters starting at 'c'. The range of
* characters in the half-open interval `[c, c + len)` must be valid.
*/
constexpr StringData(const char* c, size_type len) : StringData(_checkedView(c, len)) {}
/**
* Constructs a StringData with iterator range [first, last). `first` points to the beginning of
* the string. `last` points to the position past the end of the string.
*
* The constraint on `End` avoids competing with the `(ptr, len)` constructor.
*
* We accept whatever `std::string_view` accepts, as `std::string_view` already does advanced
* concepts checks on these arguments.
*/
template <typename It, typename End>
requires(std::constructible_from<std::string_view, It, End> &&
!std::convertible_to<End, size_type>)
constexpr StringData(It first, End last) : _sv{first, last} {}
explicit operator std::string() const {
return std::string{_sv};
}
explicit constexpr operator std::string_view() const noexcept {
return _sv;
}
//
// iterators
//
constexpr const_iterator begin() const noexcept {
return _sv.begin();
}
constexpr const_iterator end() const noexcept {
return _sv.end();
}
constexpr const_iterator cbegin() const noexcept {
return _sv.cbegin();
}
constexpr const_iterator cend() const noexcept {
return _sv.cend();
}
constexpr const_reverse_iterator rbegin() const noexcept {
return _sv.rbegin();
}
constexpr const_reverse_iterator rend() const noexcept {
return _sv.rend();
}
constexpr const_reverse_iterator crbegin() const noexcept {
return _sv.crbegin();
}
constexpr const_reverse_iterator crend() const noexcept {
return _sv.crend();
}
//
// accessors
//
constexpr const_reference operator[](size_t pos) const {
if (kDebugBuild && !(pos < size()))
invariant(pos < size(), "StringData index out of range");
return _sv[pos];
}
constexpr const_reference at(size_t pos) const {
return _sv.at(pos);
}
constexpr const_reference back() const {
return _sv.back();
}
constexpr const_reference front() const {
return _sv.front();
}
constexpr const char* data() const noexcept {
return _sv.data();
}
//
// Capacity
//
constexpr bool empty() const noexcept {
return _sv.empty();
}
constexpr size_type size() const noexcept {
return _sv.size();
}
constexpr size_type length() const noexcept {
return _sv.length();
}
constexpr size_type max_size() const noexcept {
return _sv.max_size();
}
//
// Modifiers
//
/** Moves the front of the view forward by n characters. Requires n < size. */
constexpr void remove_prefix(size_type n) {
_sv.remove_prefix(n);
}
/** Moves the end of the view back by n characters. Requires n < size. */
constexpr void remove_suffix(size_type n) {
_sv.remove_suffix(n);
}
constexpr void swap(StringData& v) noexcept {
_sv.swap(v._sv);
}
//
// Operations
//
constexpr size_type copy(char* dest, size_type count, size_type pos = 0) const {
return _sv.copy(dest, count, pos);
}
constexpr StringData substr(size_type pos = 0, size_type n = npos) const {
return StringData{_sv.substr(pos, n)};
}
/**
* Returns <0, 0, or >0 if 'this' is less, equal, or greater than 'v' in
* lexicographical order.
*/
constexpr int compare(StringData v) const noexcept {
return _sv.compare(v._sv);
}
constexpr int compare(size_type pos1, size_type count1, StringData v) const {
return _sv.compare(pos1, count1, v._sv);
}
constexpr int compare(
size_type pos1, size_type count1, StringData v, size_type pos2, size_type count2) const {
return _sv.compare(pos1, count1, v._sv, pos2, count2);
}
constexpr int compare(const char* s) const {
return _sv.compare(s);
}
constexpr int compare(size_type pos1, size_type count1, const char* s) const {
return _sv.compare(pos1, count1, s);
}
constexpr int compare(size_type pos1, size_type count1, const char* s, size_type count2) const {
return _sv.compare(pos1, count1, s, count2);
}
/** True if 'prefix' is a substring anchored at begin. */
constexpr bool starts_with(StringData v) const noexcept {
return _sv.starts_with(v._sv);
}
constexpr bool starts_with(char ch) const noexcept {
return _sv.starts_with(ch);
}
constexpr bool starts_with(const char* s) const {
return _sv.starts_with(s);
}
/** True if 'suffix' is a substring anchored at end. */
constexpr bool ends_with(StringData v) const noexcept {
return _sv.ends_with(v._sv);
}
constexpr bool ends_with(char ch) const noexcept {
return _sv.ends_with(ch);
}
constexpr bool ends_with(const char* s) const {
return _sv.ends_with(s);
}
constexpr bool contains(StringData v) const noexcept {
return _sv.find(v._sv) != npos;
}
constexpr bool contains(char ch) const noexcept {
return _sv.find(ch) != npos;
}
constexpr bool contains(const char* s) const {
return _sv.find(s) != npos;
}
/** The "find" family of functions have identical overload sets. */
#define STRING_DATA_DEFINE_FIND_OVERLOADS_(func, posDefault) \
constexpr size_type func(StringData v, size_type pos = posDefault) const noexcept { \
return _sv.func(v._sv, pos); \
} \
constexpr size_type func(char ch, size_type pos = posDefault) const noexcept { \
return _sv.func(ch, pos); \
} \
constexpr size_type func(const char* s, size_type pos, size_type count) const { \
return _sv.func(s, pos, count); \
} \
constexpr size_type func(const char* s, size_type pos = posDefault) const { \
return _sv.func(s, pos); \
}
STRING_DATA_DEFINE_FIND_OVERLOADS_(find, 0)
STRING_DATA_DEFINE_FIND_OVERLOADS_(rfind, npos)
STRING_DATA_DEFINE_FIND_OVERLOADS_(find_first_of, 0)
STRING_DATA_DEFINE_FIND_OVERLOADS_(find_last_of, npos)
STRING_DATA_DEFINE_FIND_OVERLOADS_(find_first_not_of, 0)
STRING_DATA_DEFINE_FIND_OVERLOADS_(find_last_not_of, npos)
#undef STRING_DATA_FIND_OVERLOADS_
friend constexpr auto operator<=>(StringData a, StringData b) = default;
friend constexpr bool operator==(StringData a, StringData b) = default;
/** absl::Hash ADL hook (behave exactly as std::string_view). */
template <typename H>
friend H AbslHashValue(H h, StringData sd) {
return H::combine(std::move(h), std::string_view{sd});
}
private:
explicit constexpr StringData(std::string_view sv) : _sv{sv} {}
static constexpr std::string_view _checkedView(const char* c, size_type len) {
if constexpr (kDebugBuild) {
if (MONGO_unlikely(!c && (len != 0)))
invariant(0, "StringData(nullptr,len) requires len==0");
}
return std::string_view{c, len};
}
std::string_view _sv;
};
// Adds support for boost::Hash.
size_t hash_value(StringData sd);
std::ostream& operator<<(std::ostream& os, StringData v);
inline std::string& operator+=(std::string& a, StringData b) {
return a += std::string_view{b};
}
/** Not supported by `std::string_view`. */
inline std::string operator+(std::string a, StringData b) {
return a += b;
}
/** Not supported by `std::string_view`. */
inline std::string operator+(StringData a, std::string b) {
return b.insert(0, std::string_view{a});
}
/**
* Converts `StringData` -> `std::string_view`.
* `std::string_view` is banned in favor of `StringData`.
* Use this where `std::string_view` must be used instead.
*/
constexpr std::string_view toStdStringViewForInterop(StringData s) {
return {s.data(), s.size()};
}
/**
* Converts `std::string_view` -> `StringData`.
* `std::string_view` is banned in favor of `StringData`.
* Use this where `std::string_view` must be used instead.
*/
constexpr StringData toStringDataForInterop(std::string_view s) {
return {s.data(), s.size()};
}
inline namespace literals {
/**
* Makes a constexpr StringData from a user defined literal (e.g. "hello"_sd).
* This allows for constexpr creation of `StringData` that are known at compile time.
*/
constexpr StringData operator""_sd(const char* c, std::size_t len) {
return {c, len};
}
} // namespace literals
} // namespace mongo
namespace std {
template <>
struct hash<mongo::StringData> {
size_t operator()(mongo::StringData s) const noexcept {
return hash<std::string_view>{}(toStdStringViewForInterop(s));
}
};
} // namespace std
namespace fmt {
template <>
class formatter<mongo::StringData> : private formatter<std::string_view> {
using Base = formatter<std::string_view>;
public:
using Base::parse;
auto format(mongo::StringData s, auto& fc) const {
return Base::format(std::string_view{s}, fc);
}
};
} // namespace fmt