userver: userver/utils/zstring_view.hpp Source File
Loading...
Searching...
No Matches
zstring_view.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/zstring_view.hpp
4/// @brief @copybrief utils::zstring_view
5/// @ingroup userver_universal
6
7#include <concepts>
8#include <string>
9#include <string_view>
10
11#include <fmt/format.h>
12
13#include <userver/formats/serialize/to.hpp>
14
15USERVER_NAMESPACE_BEGIN
16
17namespace utils {
18
19// Forward declaration
20[[noreturn]] void AbortWithStacktrace(std::string_view message) noexcept;
21
22/// @ingroup userver_containers
23///
24/// @brief Non-empty string view type that guarantees null-termination and has a `c_str()` member function.
25class zstring_view : public std::string_view { // NOLINT(readability-identifier-naming)
26public:
27 zstring_view() = delete;
28 zstring_view(const zstring_view& str) = default;
29
30 constexpr zstring_view(const char* str) noexcept : std::string_view{str} {
31 // data()[size()] == '\0' is guaranteed by std::string_view that calls std::strlen(str)
32 }
33
34 zstring_view(const std::string& str) noexcept : std::string_view{str} {}
35
36 zstring_view& operator=(std::string_view) = delete;
37 zstring_view& operator=(const zstring_view&) = default;
38
39 void remove_suffix(std::size_t) = delete; // zstring_view becomes not null-terminated after that function call
40 void swap(std::string_view&) = delete; // zstring_view may become not null-terminated after that function call
41 void swap(zstring_view& other) noexcept { std::string_view::swap(other); }
42
43 constexpr const char* c_str() const noexcept { return std::string_view::data(); }
44
45 /// Constructs a zstring_view from a pointer and size.
46 /// @warning `str[len]` should be '\0'.
47 static constexpr zstring_view UnsafeMake(const char* str, std::size_t len) noexcept {
48 return zstring_view{str, len};
49 }
50
51 friend constexpr auto operator<=>(zstring_view lhs, zstring_view rhs) noexcept = default;
52
53 friend constexpr auto operator<=>(zstring_view lhs, const std::convertible_to<std::string_view> auto& rhs)
54 noexcept {
55 return std::string_view{lhs} <=> std::string_view{rhs};
56 }
57
58 friend constexpr bool operator==(zstring_view lhs, const std::convertible_to<std::string_view> auto& rhs) noexcept {
59 return std::string_view{lhs} == std::string_view{rhs};
60 }
61
62private:
63 constexpr zstring_view(const char* str, std::size_t len) noexcept : std::string_view{str, len} {
64#ifndef NDEBUG
65 if (!str || str[len] != 0) {
66 USERVER_NAMESPACE::utils::AbortWithStacktrace("`str` should be not null and should be null terminated");
67 }
68#endif
69 }
70};
71
72template <class Value>
73Value Serialize(zstring_view view, formats::serialize::To<Value>) {
74 return typename Value::Builder(std::string_view{view}).ExtractValue();
75}
76
77} // namespace utils
78
79USERVER_NAMESPACE_END
80
81template <>
82struct fmt::formatter<USERVER_NAMESPACE::utils::zstring_view, char> : fmt::formatter<std::string_view> {};
83
84namespace fmt {
85
86// Allow fmt::runtime() to work with utils::zstring_view
87template <class... NotUsed>
88inline auto runtime(USERVER_NAMESPACE::utils::zstring_view s, NotUsed...) // NOLINT(readability-identifier-naming)
89 -> decltype(fmt::runtime(std::string_view{s})) {
90 static_assert(sizeof...(NotUsed) == 0);
91 return fmt::runtime(std::string_view{s});
92}
93
94} // namespace fmt