Phasor 3.3.0
Stack VM based Programming Language
Loading...
Searching...
No Matches
PhasorString.hpp
Go to the documentation of this file.
1#pragma once
2#include <algorithm>
3#include <cassert>
4#include "phsint.hpp"
5#include <cstring>
6#include <ostream>
7#include <stdexcept>
8#include <string_view>
9#include <format>
10
11inline constexpr std::size_t kSSOCapacity = 23;
12
13static_assert(kSSOCapacity >= 1, "SSO capacity must be at least 1");
14static_assert(kSSOCapacity <= 255, "SSO capacity must fit in a u8");
15
17namespace Phasor
18{
19
20/*
21 * @brief Phasor SSO String
22 */
23class PhsString {
24public:
25 static constexpr std::size_t SSO_CAPACITY = kSSOCapacity;
26 static constexpr std::size_t npos = std::string::npos;
27
28 using value_type = char;
29 using size_type = std::size_t;
30 using difference_type = std::ptrdiff_t;
31 using reference = char&;
32 using const_reference = const char&;
33 using pointer = char*;
34 using const_pointer = const char*;
35 using iterator = char*;
36 using const_iterator = const char*;
37 using reverse_iterator = std::reverse_iterator<iterator>;
38 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
39
40 PhsString() noexcept : m_store{SmallBuf{}} {}
41
42 PhsString(const char* s) : PhsString(s, s ? std::strlen(s) : 0) {}
43
44 PhsString(const char* s, std::size_t n) {
45 if (n <= SSO_CAPACITY) m_store = SmallBuf{s, n};
46 else m_store = std::string{s, n};
47 }
48
49 PhsString(std::string_view sv)
50 : PhsString(sv.data(), sv.size()) {}
51
52 PhsString(const std::string& s)
53 : PhsString(s.data(), s.size()) {}
54
55 PhsString(std::size_t n, char c) {
56 if (n <= SSO_CAPACITY) {
57 SmallBuf buf{};
58 std::memset(buf.data, c, n);
59 buf.data[n] = '\0';
60 buf.len = static_cast<u8>(n);
61 m_store = buf;
62 } else {
63 m_store = std::string(n, c);
64 }
65 }
66
67 PhsString(const PhsString&) = default;
68 PhsString(PhsString&&) noexcept = default;
69 PhsString& operator=(const PhsString&) = default;
70 PhsString& operator=(PhsString&&) noexcept = default;
71 ~PhsString() = default;
72
73 PhsString& operator=(const char* s) { return *this = PhsString{s}; }
74 PhsString& operator=(std::string_view sv){ return *this = PhsString{sv}; }
75
76 [[nodiscard]] std::size_t size() const noexcept { return is_small() ? sm().len : lg().size(); }
77 [[nodiscard]] std::size_t length() const noexcept { return size(); }
78 [[nodiscard]] bool empty() const noexcept { return size() == 0; }
79
80 [[nodiscard]] std::size_t capacity() const noexcept {
81 return is_small() ? SSO_CAPACITY : lg().capacity();
82 }
83 [[nodiscard]] std::size_t max_size() const noexcept {
84 return std::string{}.max_size();
85 }
86
87 [[nodiscard]] bool is_small() const noexcept { return std::holds_alternative<SmallBuf>(m_store); }
88 [[nodiscard]] bool is_heap_allocated() const noexcept { return !is_small(); }
89
90 [[nodiscard]] const char* data() const noexcept { return is_small() ? sm().data : lg().data(); }
91 [[nodiscard]] char* data() noexcept { return is_small() ? sm().data : lg().data(); }
92 [[nodiscard]] const char* c_str() const noexcept { return data(); }
93 [[nodiscard]] std::string_view view() const noexcept { return {data(), size()}; }
94
95 char& operator[](std::size_t i) noexcept { return data()[i]; }
96 const char& operator[](std::size_t i) const noexcept { return data()[i]; }
97
98 char& at(std::size_t i) {
99 if (i >= size()) throw std::out_of_range{"PhsString::at: index out of range"};
100 return data()[i];
101 }
102 const char& at(std::size_t i) const {
103 if (i >= size()) throw std::out_of_range{"PhsString::at: index out of range"};
104 return data()[i];
105 }
106
107 char& front() noexcept { assert(!empty()); return data()[0]; }
108 const char& front() const noexcept { assert(!empty()); return data()[0]; }
109 char& back() noexcept { assert(!empty()); return data()[size() - 1]; }
110 const char& back() const noexcept { assert(!empty()); return data()[size() - 1]; }
111
112
113 iterator begin() noexcept { return data(); }
114 iterator end() noexcept { return data() + size(); }
115 const_iterator begin() const noexcept { return data(); }
116 const_iterator end() const noexcept { return data() + size(); }
117 const_iterator cbegin() const noexcept { return begin(); }
118 const_iterator cend() const noexcept { return end(); }
119
120 reverse_iterator rbegin() noexcept { return reverse_iterator{end()}; }
121 reverse_iterator rend() noexcept { return reverse_iterator{begin()}; }
124 const_reverse_iterator crbegin() const noexcept { return rbegin(); }
125 const_reverse_iterator crend() const noexcept { return rend(); }
126
127
128 void clear() noexcept {
129 if (is_small()) { sm().data[0] = '\0'; sm().len = 0; }
130 else { lg().clear(); }
131 }
132
133 PhsString& append(const char* s, std::size_t n) {
134 const std::size_t old_sz = size();
135 const std::size_t new_sz = old_sz + n;
136
137 if (is_small()) {
138 if (new_sz <= SSO_CAPACITY) {
139 std::memcpy(sm().data + old_sz, s, n);
140 sm().data[new_sz] = '\0';
141 sm().len = static_cast<u8>(new_sz);
142 return *this;
143 }
144 std::string promoted{sm().data, old_sz};
145 promoted.append(s, n);
146 m_store = std::move(promoted);
147 } else {
148 lg().append(s, n);
149 }
150 return *this;
151 }
152
153 PhsString& append(std::string_view sv) { return append(sv.data(), sv.size()); }
154 PhsString& append(const char* s) { return append(s, std::strlen(s)); }
155 PhsString& append(std::size_t n, char c) {
156 const std::size_t old_sz = size();
157 const std::size_t new_sz = old_sz + n;
158 if (is_small()) {
159 if (new_sz <= SSO_CAPACITY) {
160 std::memset(sm().data + old_sz, c, n);
161 sm().data[new_sz] = '\0';
162 sm().len = static_cast<u8>(new_sz);
163 return *this;
164 }
165 std::string promoted{sm().data, old_sz};
166 promoted.append(n, c);
167 m_store = std::move(promoted);
168 } else {
169 lg().append(n, c);
170 }
171 return *this;
172 }
173
174 PhsString& operator+=(std::string_view sv) { return append(sv.data(), sv.size()); }
175 PhsString& operator+=(const char* s) { return append(s); }
176 PhsString& operator+=(char c) { return append(&c, 1); }
177
178 void push_back(char c) { append(&c, 1); }
179 void pop_back() noexcept {
180 assert(!empty());
181 if (is_small()) sm().data[--sm().len] = '\0';
182 else lg().pop_back();
183 }
184
185 void resize(std::size_t n, char c = '\0') {
186 const std::size_t old_sz = size();
187 if (n == old_sz) { return; }
188 else if (n < old_sz) {
189 if (is_small()) { sm().data[n] = '\0'; sm().len = static_cast<u8>(n); }
190 else { lg().resize(n); }
191 } else {
192 append(n - old_sz, c);
193 }
194 }
195
196 std::size_t find(std::string_view sv, std::size_t pos = 0) const noexcept { return view().find(sv, pos); }
197 std::size_t find(char c, std::size_t pos = 0) const noexcept { return view().find(c, pos); }
198 std::size_t rfind(std::string_view sv, std::size_t pos = npos) const noexcept { return view().rfind(sv, pos); }
199 std::size_t rfind(char c, std::size_t pos = npos) const noexcept { return view().rfind(c, pos); }
200
201 std::size_t find_first_of (std::string_view sv, std::size_t pos = 0) const noexcept { return view().find_first_of(sv, pos); }
202 std::size_t find_last_of (std::string_view sv, std::size_t pos = npos)const noexcept { return view().find_last_of(sv, pos); }
203 std::size_t find_first_not_of(std::string_view sv, std::size_t pos = 0) const noexcept { return view().find_first_not_of(sv, pos); }
204 std::size_t find_last_not_of (std::string_view sv, std::size_t pos = npos)const noexcept { return view().find_last_not_of(sv, pos); }
205
206 int compare(std::string_view sv) const noexcept { return view().compare(sv); }
207
208 [[nodiscard]] bool starts_with(std::string_view sv) const noexcept { return view().starts_with(sv); }
209 [[nodiscard]] bool ends_with (std::string_view sv) const noexcept { return view().ends_with(sv); }
210 [[nodiscard]] bool contains (std::string_view sv) const noexcept { return find(sv) != npos; }
211
212 [[nodiscard]] PhsString substr(std::size_t pos = 0, std::size_t len = npos) const {
213 const std::size_t sz = size();
214 if (pos > sz) throw std::out_of_range{"PhsString::substr: pos out of range"};
215 return PhsString{data() + pos, std::min(len, sz - pos)};
216 }
217
218 [[nodiscard]] std::string str() const {
219 return is_small() ? std::string{sm().data, sm().len} : lg();
220 }
221 operator std::string() const { return str(); }
222 operator std::string_view() const noexcept { return view(); }
223
224 [[nodiscard]] std::strong_ordering operator<=>(const PhsString& o) const noexcept {
225 return view() <=> o.view();
226 }
227 [[nodiscard]] bool operator==(const PhsString& o) const noexcept {
228 return view() == o.view();
229 }
230
231 [[nodiscard]] std::strong_ordering operator<=>(std::string_view sv) const noexcept {
232 return view() <=> sv;
233 }
234 [[nodiscard]] bool operator==(std::string_view sv) const noexcept {
235 return view() == sv;
236 }
237
238 friend std::ostream& operator<<(std::ostream& os, const PhsString& s) {
239 return os.write(s.data(), static_cast<std::streamsize>(s.size()));
240 }
241
242private:
243
244 struct SmallBuf {
247
248 constexpr SmallBuf() noexcept : data{}, len{0} {}
249
250 SmallBuf(const char* s, std::size_t n) noexcept
251 : len{static_cast<u8>(n)} {
252 std::memcpy(data, s, n);
253 data[n] = '\0';
254 }
255 };
256
257 std::variant<SmallBuf, std::string> m_store;
258
259 SmallBuf& sm() noexcept { return std::get<SmallBuf>(m_store); }
260 const SmallBuf& sm() const noexcept { return std::get<SmallBuf>(m_store); }
261 std::string& lg() noexcept { return std::get<std::string>(m_store); }
262 const std::string& lg() const noexcept { return std::get<std::string>(m_store); }
263};
264
265inline PhsString operator+(PhsString lhs, std::string_view rhs) { return lhs += rhs; }
266inline PhsString operator+(PhsString lhs, char rhs) { return lhs += rhs; }
267inline PhsString operator+(std::string_view lhs, PhsString rhs) {
268 return PhsString{lhs} += rhs;
269}
270inline PhsString operator+(PhsString lhs, const PhsString& rhs) {
271 return lhs += rhs.view();
272}
273
274} // namespace Phasor
275
276template <>
277struct std::hash<Phasor::PhsString> {
278 std::size_t operator()(const Phasor::PhsString& s) const noexcept {
279 return std::hash<std::string_view>{}(s.view());
280 }
281};
282
283template <>
284struct std::formatter<Phasor::PhsString> : std::formatter<std::string_view>
285{
286 template <typename FormatContext>
287 auto format(const Phasor::PhsString &s, FormatContext &ctx) const
288 {
289 return std::formatter<std::string_view>::format(s.view(), ctx);
290 }
291};
constexpr std::size_t kSSOCapacity
void pop_back() noexcept
const char * c_str() const noexcept
PhsString & append(std::size_t n, char c)
const char & const_reference
PhsString substr(std::size_t pos=0, std::size_t len=npos) const
char & back() noexcept
const char & back() const noexcept
std::size_t find_first_of(std::string_view sv, std::size_t pos=0) const noexcept
const char & at(std::size_t i) const
static constexpr std::size_t SSO_CAPACITY
PhsString & operator+=(const char *s)
PhsString(const char *s, std::size_t n)
std::reverse_iterator< const_iterator > const_reverse_iterator
PhsString(PhsString &&) noexcept=default
std::ptrdiff_t difference_type
void push_back(char c)
const_iterator cbegin() const noexcept
reverse_iterator rend() noexcept
std::strong_ordering operator<=>(const PhsString &o) const noexcept
char * data() noexcept
bool is_heap_allocated() const noexcept
SmallBuf & sm() noexcept
const_reverse_iterator rbegin() const noexcept
std::size_t size() const noexcept
bool ends_with(std::string_view sv) const noexcept
std::size_t length() const noexcept
void clear() noexcept
std::string str() const
const_iterator cend() const noexcept
std::size_t find_first_not_of(std::string_view sv, std::size_t pos=0) const noexcept
PhsString(std::string_view sv)
std::string_view view() const noexcept
std::size_t find_last_not_of(std::string_view sv, std::size_t pos=npos) const noexcept
const SmallBuf & sm() const noexcept
std::reverse_iterator< iterator > reverse_iterator
std::size_t rfind(char c, std::size_t pos=npos) const noexcept
iterator end() noexcept
std::variant< SmallBuf, std::string > m_store
const_reverse_iterator rend() const noexcept
const_reverse_iterator crbegin() const noexcept
void resize(std::size_t n, char c='\0')
bool empty() const noexcept
bool starts_with(std::string_view sv) const noexcept
PhsString(std::size_t n, char c)
const char & front() const noexcept
PhsString & append(std::string_view sv)
PhsString & append(const char *s, std::size_t n)
const std::string & lg() const noexcept
PhsString & operator+=(std::string_view sv)
static constexpr std::size_t npos
std::size_t find(std::string_view sv, std::size_t pos=0) const noexcept
std::string & lg() noexcept
bool operator==(const PhsString &o) const noexcept
const_iterator end() const noexcept
int compare(std::string_view sv) const noexcept
bool operator==(std::string_view sv) const noexcept
std::size_t size_type
PhsString(const std::string &s)
std::strong_ordering operator<=>(std::string_view sv) const noexcept
iterator begin() noexcept
std::size_t find(char c, std::size_t pos=0) const noexcept
PhsString & operator+=(char c)
std::size_t max_size() const noexcept
friend std::ostream & operator<<(std::ostream &os, const PhsString &s)
char & operator[](std::size_t i) noexcept
PhsString(const char *s)
char & front() noexcept
std::size_t capacity() const noexcept
const char * const_pointer
PhsString(const PhsString &)=default
std::size_t rfind(std::string_view sv, std::size_t pos=npos) const noexcept
const char * data() const noexcept
const char * const_iterator
const char & operator[](std::size_t i) const noexcept
PhsString & operator=(std::string_view sv)
const_iterator begin() const noexcept
PhsString & append(const char *s)
const_reverse_iterator crend() const noexcept
std::size_t find_last_of(std::string_view sv, std::size_t pos=npos) const noexcept
bool is_small() const noexcept
bool contains(std::string_view sv) const noexcept
reverse_iterator rbegin() noexcept
char & at(std::size_t i)
static Phasor::u64 s[2]
Definition random.cpp:7
The Phasor Programming Language and Runtime.
Definition AST.hpp:13
uint8_t u8
Definition phsint.hpp:9
PhsString operator+(PhsString lhs, std::string_view rhs)
constexpr SmallBuf() noexcept
SmallBuf(const char *s, std::size_t n) noexcept
char data[SSO_CAPACITY+1]
auto format(const Phasor::PhsString &s, FormatContext &ctx) const
std::size_t operator()(const Phasor::PhsString &s) const noexcept