ESPHome 2026.8.0
Loading...
Searching...
No Matches
string_ref.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <cstring>
5#include <iterator>
6#include <memory>
7#include <string>
9
10#ifdef USE_JSON
12#endif // USE_JSON
13
14#ifdef USE_ESP8266
15#include <pgmspace.h>
16#endif // USE_ESP8266
17
18namespace esphome {
19
26class StringRef {
27 public:
28 using traits_type = std::char_traits<char>;
29 using value_type = traits_type::char_type;
30 using allocator_type = std::allocator<char>;
31 using size_type = std::allocator_traits<allocator_type>::size_type;
32 using difference_type = std::allocator_traits<allocator_type>::difference_type;
33 using const_reference = const value_type &;
34 using const_pointer = const value_type *;
36 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
37
38 constexpr StringRef() : base_(""), len_(0) {}
39 explicit StringRef(const std::string &s) : base_(s.c_str()), len_(s.size()) {}
40 explicit StringRef(const char *s) : base_(s), len_(strlen(s)) {}
41 constexpr StringRef(const char *s, size_t n) : base_(s), len_(n) {}
42 template<typename CharT>
43 constexpr StringRef(const CharT *s, size_t n) : base_(reinterpret_cast<const char *>(s)), len_(n) {}
44 template<typename InputIt>
45 StringRef(InputIt first, InputIt last)
46 : base_(reinterpret_cast<const char *>(&*first)), len_(std::distance(first, last)) {}
47 template<typename InputIt>
48 StringRef(InputIt *first, InputIt *last)
49 : base_(reinterpret_cast<const char *>(first)), len_(std::distance(first, last)) {}
50 template<typename CharT, size_t N> constexpr static StringRef from_lit(const CharT (&s)[N]) {
51 return StringRef{s, N - 1};
52 }
53 static StringRef from_maybe_nullptr(const char *s) {
54 if (s == nullptr) {
55 return StringRef();
56 }
57
58 return StringRef(s);
59 }
60
61 constexpr const_iterator begin() const { return base_; };
62 constexpr const_iterator cbegin() const { return base_; };
63
64 constexpr const_iterator end() const { return base_ + len_; };
65 constexpr const_iterator cend() const { return base_ + len_; };
66
67 const_reverse_iterator rbegin() const { return const_reverse_iterator{base_ + len_}; }
68 const_reverse_iterator crbegin() const { return const_reverse_iterator{base_ + len_}; }
69
72
73 constexpr const char *c_str() const { return base_; }
74 constexpr size_type size() const { return len_; }
75 constexpr size_type length() const { return len_; }
76 constexpr bool empty() const { return len_ == 0; }
77 constexpr const_reference operator[](size_type pos) const { return *(base_ + pos); }
78
80 bool starts_with(const StringRef &prefix) const {
81 return len_ >= prefix.len_ && std::memcmp(base_, prefix.base_, prefix.len_) == 0;
82 }
83 bool starts_with(const char *prefix) const { return this->starts_with(StringRef(prefix)); }
84 bool starts_with(const std::string &prefix) const { return this->starts_with(StringRef(prefix)); }
85
87 size_type copy(char *dest, size_type count, size_type pos = 0) const {
88 if (pos >= len_)
89 return 0;
90 size_type actual = (count > len_ - pos) ? len_ - pos : count;
91 std::memcpy(dest, base_ + pos, actual);
92 return actual;
93 }
94
95 std::string str() const { return std::string(base_, len_); }
96 const uint8_t *byte() const { return reinterpret_cast<const uint8_t *>(base_); }
97
98 operator std::string() const { return str(); }
99
101 int compare(const StringRef &other) const {
102 int result = std::memcmp(base_, other.base_, std::min(len_, other.len_));
103 if (result != 0)
104 return result;
105 if (len_ < other.len_)
106 return -1;
107 if (len_ > other.len_)
108 return 1;
109 return 0;
110 }
111 int compare(const char *s) const { return compare(StringRef(s)); }
112 int compare(const std::string &s) const { return compare(StringRef(s)); }
113
116 size_type find(const char *s, size_type pos = 0) const {
117 if (pos >= len_)
118 return std::string::npos;
119 const char *result = std::strstr(base_ + pos, s);
120 // Verify entire match is within bounds (strstr searches to null terminator)
121 if (result && result + std::strlen(s) <= base_ + len_)
122 return static_cast<size_type>(result - base_);
123 return std::string::npos;
124 }
125 size_type find(char c, size_type pos = 0) const {
126 if (pos >= len_)
127 return std::string::npos;
128 const void *result = std::memchr(base_ + pos, static_cast<unsigned char>(c), len_ - pos);
129 return result ? static_cast<size_type>(static_cast<const char *>(result) - base_) : std::string::npos;
130 }
131
133 std::string substr(size_type pos = 0, size_type count = std::string::npos) const {
134 if (pos >= len_)
135 return std::string();
136 size_type actual_count = (count == std::string::npos || pos + count > len_) ? len_ - pos : count;
137 return std::string(base_ + pos, actual_count);
138 }
139
140 private:
141 const char *base_;
142 size_type len_;
143};
144
145inline bool operator==(const StringRef &lhs, const StringRef &rhs) {
146 return lhs.size() == rhs.size() && std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
147}
148
149inline bool operator==(const StringRef &lhs, const std::string &rhs) {
150 return lhs.size() == rhs.size() && std::equal(std::begin(lhs), std::end(lhs), std::begin(rhs));
151}
152
153inline bool operator==(const std::string &lhs, const StringRef &rhs) { return rhs == lhs; }
154
155inline bool operator==(const StringRef &lhs, const char *rhs) {
156 return lhs.size() == strlen(rhs) && std::equal(std::begin(lhs), std::end(lhs), rhs);
157}
158
159inline bool operator==(const char *lhs, const StringRef &rhs) { return rhs == lhs; }
160
161inline bool operator!=(const StringRef &lhs, const StringRef &rhs) { return !(lhs == rhs); }
162
163inline bool operator!=(const StringRef &lhs, const std::string &rhs) { return !(lhs == rhs); }
164
165inline bool operator!=(const std::string &lhs, const StringRef &rhs) { return !(rhs == lhs); }
166
167inline bool operator!=(const StringRef &lhs, const char *rhs) { return !(lhs == rhs); }
168
169inline bool operator!=(const char *lhs, const StringRef &rhs) { return !(rhs == lhs); }
170
171#ifdef USE_ESP8266
172inline bool operator==(const StringRef &lhs, const __FlashStringHelper *rhs) {
173 PGM_P p = reinterpret_cast<PGM_P>(rhs);
174 size_t rhs_len = strlen_P(p);
175 if (lhs.size() != rhs_len) {
176 return false;
177 }
178 return memcmp_P(lhs.c_str(), p, rhs_len) == 0;
179}
180
181inline bool operator==(const __FlashStringHelper *lhs, const StringRef &rhs) { return rhs == lhs; }
182
183inline bool operator!=(const StringRef &lhs, const __FlashStringHelper *rhs) { return !(lhs == rhs); }
184
185inline bool operator!=(const __FlashStringHelper *lhs, const StringRef &rhs) { return !(rhs == lhs); }
186#endif // USE_ESP8266
187
188inline bool operator<(const StringRef &lhs, const StringRef &rhs) {
189 return std::lexicographical_compare(std::begin(lhs), std::end(lhs), std::begin(rhs), std::end(rhs));
190}
191
192inline std::string &operator+=(std::string &lhs, const StringRef &rhs) {
193 lhs.append(rhs.c_str(), rhs.size());
194 return lhs;
195}
196
197inline std::string operator+(const char *lhs, const StringRef &rhs) {
198 auto str = std::string(lhs);
199 str.append(rhs.c_str(), rhs.size());
200 return str;
201}
202
203inline std::string operator+(const StringRef &lhs, const char *rhs) {
204 auto str = lhs.str();
205 str.append(rhs);
206 return str;
207}
208
209inline std::string operator+(const StringRef &lhs, const std::string &rhs) {
210 auto str = lhs.str();
211 str.append(rhs);
212 return str;
213}
214
215inline std::string operator+(const std::string &lhs, const StringRef &rhs) {
216 std::string str(lhs);
217 str.append(rhs.c_str(), rhs.size());
218 return str;
219}
220// String conversion functions for ADL compatibility (allows stoi(x) where x is StringRef)
221// Must be in esphome namespace for ADL to find them. Uses strtol/strtod directly to avoid heap allocation.
222namespace internal {
223// NOLINTBEGIN(google-runtime-int)
224template<typename R, typename F> inline R parse_number(const StringRef &str, size_t *pos, F conv) {
225 char *end;
226 R result = conv(str.c_str(), &end);
227 // Set pos to 0 on conversion failure (when no characters consumed), otherwise index after number
228 if (pos)
229 *pos = (end == str.c_str()) ? 0 : static_cast<size_t>(end - str.c_str());
230 return result;
231}
232template<typename R, typename F> inline R parse_number(const StringRef &str, size_t *pos, int base, F conv) {
233 char *end;
234 R result = conv(str.c_str(), &end, base);
235 // Set pos to 0 on conversion failure (when no characters consumed), otherwise index after number
236 if (pos)
237 *pos = (end == str.c_str()) ? 0 : static_cast<size_t>(end - str.c_str());
238 return result;
239}
240// NOLINTEND(google-runtime-int)
241} // namespace internal
242// NOLINTBEGIN(readability-identifier-naming,google-runtime-int)
243inline int stoi(const StringRef &str, size_t *pos = nullptr, int base = 10) {
244 return static_cast<int>(internal::parse_number<long>(str, pos, base, std::strtol));
245}
246inline long stol(const StringRef &str, size_t *pos = nullptr, int base = 10) {
247 return internal::parse_number<long>(str, pos, base, std::strtol);
248}
249inline float stof(const StringRef &str, size_t *pos = nullptr) {
250 return internal::parse_number<float>(str, pos, std::strtof);
251}
252inline double stod(const StringRef &str, size_t *pos = nullptr) {
253 return internal::parse_number<double>(str, pos, std::strtod);
254}
255// NOLINTEND(readability-identifier-naming,google-runtime-int)
256
257#ifdef USE_JSON
258// NOLINTNEXTLINE(readability-identifier-naming)
259inline void convertToJson(const StringRef &src, JsonVariant dst) { dst.set(src.c_str()); }
260#endif // USE_JSON
261
262} // namespace esphome
StringRef is a reference to a string owned by something else.
Definition string_ref.h:26
bool starts_with(const char *prefix) const
Definition string_ref.h:83
StringRef(const std::string &s)
Definition string_ref.h:39
std::allocator< char > allocator_type
Definition string_ref.h:30
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition string_ref.h:36
size_type find(char c, size_type pos=0) const
Definition string_ref.h:125
const_reverse_iterator crend() const
Definition string_ref.h:71
constexpr const char * c_str() const
Definition string_ref.h:73
bool starts_with(const std::string &prefix) const
Definition string_ref.h:84
constexpr StringRef(const CharT *s, size_t n)
Definition string_ref.h:43
std::char_traits< char > traits_type
Definition string_ref.h:28
const value_type * const_pointer
Definition string_ref.h:34
constexpr size_type length() const
Definition string_ref.h:75
int compare(const StringRef &other) const
Compare (compatible with std::string::compare)
Definition string_ref.h:101
size_type find(const char *s, size_type pos=0) const
Find first occurrence of substring, returns std::string::npos if not found.
Definition string_ref.h:116
traits_type::char_type value_type
Definition string_ref.h:29
constexpr const_iterator cend() const
Definition string_ref.h:65
constexpr const_reference operator[](size_type pos) const
Definition string_ref.h:77
size_type copy(char *dest, size_type count, size_type pos=0) const
Copy characters to destination buffer (std::string::copy-like, but returns 0 instead of throwing on o...
Definition string_ref.h:87
constexpr const_iterator begin() const
Definition string_ref.h:61
int compare(const char *s) const
Definition string_ref.h:111
constexpr StringRef(const char *s, size_t n)
Definition string_ref.h:41
bool starts_with(const StringRef &prefix) const
True if the view begins with the given prefix (std::string::starts_with-like)
Definition string_ref.h:80
StringRef(const char *s)
Definition string_ref.h:40
constexpr bool empty() const
Definition string_ref.h:76
const_reverse_iterator rbegin() const
Definition string_ref.h:67
constexpr size_type size() const
Definition string_ref.h:74
static constexpr StringRef from_lit(const CharT(&s)[N])
Definition string_ref.h:50
constexpr const_iterator end() const
Definition string_ref.h:64
std::string str() const
Definition string_ref.h:95
std::allocator_traits< allocator_type >::size_type size_type
Definition string_ref.h:31
std::string substr(size_type pos=0, size_type count=std::string::npos) const
Return substring as std::string.
Definition string_ref.h:133
constexpr StringRef()
Definition string_ref.h:38
std::allocator_traits< allocator_type >::difference_type difference_type
Definition string_ref.h:32
StringRef(InputIt first, InputIt last)
Definition string_ref.h:45
static StringRef from_maybe_nullptr(const char *s)
Definition string_ref.h:53
int compare(const std::string &s) const
Definition string_ref.h:112
const value_type & const_reference
Definition string_ref.h:33
const_reverse_iterator rend() const
Definition string_ref.h:70
constexpr const_iterator cbegin() const
Definition string_ref.h:62
const_reverse_iterator crbegin() const
Definition string_ref.h:68
const_pointer const_iterator
Definition string_ref.h:35
const uint8_t * byte() const
Definition string_ref.h:96
StringRef(InputIt *first, InputIt *last)
Definition string_ref.h:48
R parse_number(const StringRef &str, size_t *pos, F conv)
Definition string_ref.h:224
std::string operator+(const char *lhs, const StringRef &rhs)
Definition string_ref.h:197
bool operator!=(const StringRef &lhs, const StringRef &rhs)
Definition string_ref.h:161
double stod(const StringRef &str, size_t *pos=nullptr)
Definition string_ref.h:252
void convertToJson(const StringRef &src, JsonVariant dst)
Definition string_ref.h:259
bool operator<(const StringRef &lhs, const StringRef &rhs)
Definition string_ref.h:188
std::string & operator+=(std::string &lhs, const StringRef &rhs)
Definition string_ref.h:192
size_t size_t pos
Definition helpers.h:1062
float stof(const StringRef &str, size_t *pos=nullptr)
Definition string_ref.h:249
const void * src
Definition hal.h:64
bool operator==(const StringRef &lhs, const StringRef &rhs)
Definition string_ref.h:145
int stoi(const StringRef &str, size_t *pos=nullptr, int base=10)
Definition string_ref.h:243
long stol(const StringRef &str, size_t *pos=nullptr, int base=10)
Definition string_ref.h:246
STL namespace.
uint8_t end[39]
Definition sun_gtil2.cpp:17