libGimbal 0.1.0
C17-Based Extended Standard Library and Cross-Language Runtime Framework
Loading...
Searching...
No Matches
gimbal_string.hpp
1#ifndef GIMBAL_STRING_HPP
2#define GIMBAL_STRING_HPP
3
4#include <gimbal/strings/gimbal_string_buffer.h>
5#include <gimbal/containers/gimbal_array_list.hpp>
6#include <iostream>
7#include <unordered_set>
8#include <compare>
9
10namespace gimbal {
11namespace tags {
12 struct StringBase {};
13}
14
15template<typename T, typename SFINAE>
16struct StringTraits {
17 template<typename F=T>
18 static F&& stringify(F&& value) { return std::forward<F>(value); }
19};
20
21
22template<typename T>
23concept string_base = std::is_base_of_v<gimbal::tags::StringBase, T>;
24
25class String;
26
27//make this all compatible with gimbal::Vector<char>
28
29//support string ?
30template<typename CRTP>
31class StringViewBase:
32 public tags::StringBase,
35{
36public:
37 using StringViewType = StringViewBase<CRTP>;
38 using Derived = CRTP;
40 using iterator = typename Iterable::iterator;
41 using const_iterator = typename Iterable::const_iterator;
42protected:
43 decltype(auto) str_(void) const {
44 return static_cast<const CRTP*>(this)->getString_();
45 }
46
47 decltype(auto) str_(void) {
48 return static_cast<CRTP*>(this)->getString_();
49 }
50
51public:
52
53 operator const GblStringBuffer*() const { return str_(); }
54
55
56 const char& getElement_(size_t index) const {
57 return getCString()[index];
58 }
59
60 char& getElement_(size_t index) {
61 return getCString()[index];
62 }
63
64 void setElement_(size_t index, char value) {
65 const_cast<char*>(getCString())[index] = value;
66 }
67
68 size_t getElementCount_(void) const {
69 return getLength();
70 }
71
72// Accessor wrappers
73
74 Size getStackBytes(void) const {
75 Size size = GblStringBuffer_stackBytes(str_());
76 return size;
77 }
78
79 constexpr Size getLength(void) const {
80 return GblStringBuffer_length(str_());
81 }
82
83 constexpr Size getCapacity(void) const {
84 return GblStringBuffer_capacity(str_());
85 }
86
87 Context* getContext(void) const {
88 GblContext* pCtx = GblStringBuffer_context(str_());
89 return pCtx == nullptr? nullptr : Context::fromGblObj(pCtx);
90 }
91
92 constexpr bool isEmpty(void) const {
93 GblBool empty = GblStringBuffer_empty(str_());
94 return empty;
95 }
96
97 constexpr bool isStack(void) const {
98 GblBool stack = GblStringBuffer_stack(str_());
99 return stack;
100 }
101
102 // C++-specific utils
103
104 constexpr bool isHeap(void) const {
105 return !isStack();
106 }
107
108 const char* getCString(void) const {
109 const char* pCStr = GblStringBuffer_cString(str_());
110 return pCStr;
111 }
112
113 char* getCString(void) {
114 const char* pStr = GblStringBuffer_cString(str_());
115 return const_cast<char*>(pStr);
116 }
117
118 std::string toStdString(void) const {
119 return std::string(getCString());
120 }
121
122 constexpr std::string_view toStringView(void) const {
123 return getLength()?
124 std::string_view(getCString(), getLength()) : std::string_view();
125 }
126 friend constexpr bool operator==(const Derived& lhs, const char* pRhs) noexcept {
127 return (lhs.toStringView() == std::string_view(pRhs));
128 }
129 friend constexpr decltype(auto) operator<=>(const Derived& lhs, const char* pRhs) noexcept {
130 return (lhs.toStringView() <=> std::string_view(pRhs));
131 }
132 friend constexpr bool operator==(const Derived& lhs, const std::string& rhs) noexcept {
133 return (lhs.toStdString() == rhs);
134 }
135 friend constexpr decltype(auto) operator<=>(const Derived& lhs, const std::string& rhs) noexcept {
136 return (lhs.toStdString() <=> rhs);
137 }
138#ifdef GBL_PMR_STRING
139 friend constexpr bool operator==(const Derived& lhs, const std::pmr::string& rhs) noexcept {
140 return (lhs == rhs.c_str());
141 }
142 friend constexpr decltype(auto) operator<=>(const Derived& lhs, const std::pmr::string& rhs) noexcept {
143 return (lhs.toStdString() <=> rhs);
144 }
145#endif
146 friend constexpr bool operator==(const Derived& lhs, std::string_view rhs) noexcept {
147 return (lhs.toStringView() == rhs);
148 }
149 friend constexpr decltype(auto) operator<=>(const Derived& lhs, std::string_view rhs) noexcept {
150 return (lhs.toStringView() <=> rhs);
151 }
152 friend constexpr bool operator==(const Derived& lhs, const string_base auto& rhs) {
154 return result == 0;
155 }
156 friend constexpr decltype(auto) operator<=>(const Derived& lhs, const string_base auto& rhs) {
157 return (lhs <=> rhs);
158 }
159 friend std::ostream& operator<<(std::ostream& output, const Derived& s) {
160 output << s.getCString();
162 return output;
163 }
164};
165
166class StringView final: public StringViewBase<StringView> {
167private:
168 const GblStringBuffer* pGblStr_ = nullptr;
169public:
170 StringView(void) = default;
171
172 StringView(const GblStringBuffer& gblStr):
173 pGblStr_(&gblStr) {}
174
175 StringView(const gimbal::String& string);
176
177 StringView(const GblStringBuffer* pGblStringBuffer):
178 pGblStr_(pGblStringBuffer) {}
179
180 const GblStringBuffer* getString_(void) const { return pGblStr_; }
181 bool isValid(void) const { return pGblStr_; }
182};
183
184class String:
185 public GblStringBuffer,
186 public StringViewBase<String>
187{
188public:
189
190 const GblStringBuffer* getString_(void) const {
191 return static_cast<const GblStringBuffer*>(this);
192 }
193// iterator constructors!
194 GblStringBuffer* getString_(void) {
195 return static_cast<GblStringBuffer*>(this);
196 }
197
198 //operator const GblStringBuffer*() const { return getString_(); }
199
200 // Default Ctors
201 String(std::nullptr_t, Size size=sizeof(String)):
202 String(static_cast<Context*>(nullptr), size) {}
203
204 String(Context* pCtx=nullptr, Size size=sizeof(String)):
205 String(std::string_view{}, pCtx, size) {}
206
207 // Value Ctors
208 String(const std::string& stdString, Context* pCtx=nullptr, Size size=sizeof(String)):
209 String(std::string_view{stdString.c_str()}, pCtx, size) {}
210
211#ifdef GBL_PMR_STRING
212 String(const std::pmr::string& stdPmrString, Context* pCtx=nullptr, Size size=sizeof(String)):
214#endif
215
216 String(const char* pCStr, Context* pCtx=nullptr, Size size=sizeof(String)):
217 String(pCStr? std::string_view{pCStr} : std::string_view{}, pCtx, size) {}
218
219 String(const std::string_view& stringView, Context* pCtx=nullptr, Size size=sizeof(String)) {
220 Exception::checkThrow(GblStringBuffer_construct(this,
221 GBL_STRING_VIEW(stringView.data(), stringView.length()),
222 size,
223 pCtx));
224 }
225
226 // Copy Ctor
227 String(const String& rhs, Context* pCtx=nullptr, Size size=sizeof(String)):
228 String(StringView(rhs), pCtx, size) {}
229
230 String(StringView other, Context* pCtx=nullptr, Size size=sizeof(String)):
231 String(other.toStringView(), pCtx? pCtx : other.getContext(), size) {}
232
233 // Move Ctor
234 String(String&& rhs, Context* pCtx=nullptr, Size size=sizeof(String)):
235 String(static_cast<GblStringBuffer&&>(rhs), pCtx, size) {}
236
237 String(GblStringBuffer&& rhs, Context* pCtx=nullptr, Size size=sizeof(String)):
238 String(pCtx, size)
239 {
240 *this = rhs;
241 }
242
243 ~String(void) {
244 Exception::checkThrow(GblStringBuffer_destruct(this));
245 }
246
247 static std::pair<char*, Size> take(GblStringBuffer* pGblStr) {
248 char* pCStr = nullptr;
249 Size capacity = 0;
250 Exception::checkThrow(GblStringBuffer_release(pGblStr, &pCStr, &capacity));
251 return { pCStr, capacity };
252 }
253
254 auto take(void) {
255 return take(this);
256 }
257
258 void give(std::pair<char*, Size> data) {
259 Exception::checkThrow(GblStringBuffer_acquire(this, data.first, data.second));
260 }
261
262 void clear(void) {
263 Exception::checkThrow(GblStringBuffer_clear(this));
264 }
265
266 const String& operator=(std::string_view view) {
267 Exception::checkThrow(GblStringBuffer_set(this, GBL_STRING_VIEW(view.data(), view.size())));
268 return *this;
269 }
270
271 const String& operator=(const String& rhs) {
272 return *this = StringView(rhs);
273 }
274
275 const String& operator=(StringView string) {
276 return *this = string.toStringView();
277 }
278
279 const String& operator=(const std::string& stdString) {
280 return *this = stdString.c_str();
281 }
282
283#ifdef GBL_PMR_STRING
284 const String& operator=(const std::pmr::string& stdString) {
285 return *this = stdString.c_str();
286 }
287#endif
288
289 const String& operator=(const char* pCStr) {
290 if(pCStr) return *this = std::string_view(pCStr);
291 else return *this = nullptr;
292 }
293
294 const String& operator=(std::nullptr_t) {
295 clear();
296 return *this;
297 }
298
299 const String& operator=(String&& rhs) {
300 return *this = static_cast<GblStringBuffer&&>(rhs);
301 }
302
303 const String& operator=(GblStringBuffer&& rhs) {
304 StringView rhsView(rhs);
305
306 if(getContext() == rhsView.getContext() && rhsView.isHeap()) {
307 give(take(&rhs));
308 } else { //cannot move construct!
309 *this = rhsView.toStringView();
310 }
311
312 return *this;
313 }
314
315 const String& operator+=(std::string_view view) {
316 concat(view);
317 return *this;
318 }
319
320 const String& operator+=(StringView view) {
321 return *this += view.toStringView();
322 }
323
324 void reserve(Size capacity) {
325 Exception::checkThrow(GblStringBuffer_reserve(this, capacity));
326 }
327
328 void resize(Size size) {
329 Exception::checkThrow(GblStringBuffer_resize(this, size));
330 }
331
332 void insert(const_iterator pos, const char* pString, GblSize count=0) {
333 GBL_ASSERT(pString);
334 const auto index = std::distance(cbegin(), pos);
335 Exception::checkThrow(GblStringBuffer_insert(this, index, GBL_STRING_VIEW(pString, count)));
336 // return iterator(*this, index);
337 }
338
339 void concat(std::string_view view) {
340 //insert(cend(), view.data(), view.size());
341 Exception::checkThrow(GblArrayList_append(&this->data, view.data(), view.size()));
342 }
343
344 String& vasprintf(const char* pFmt, va_list varArgs) {
345 Exception::checkThrow(GblStringBuffer_appendVPrintf(this, pFmt, varArgs));
346 return *this;
347 }
348
349 //return the actual return value?
350 String& sprintf(const char* pFmt, ...) {
351 va_list varArgs;
352 va_start(varArgs, pFmt);
353 vasprintf(pFmt, varArgs);
354 va_end(varArgs);
355 return *this;
356 }
357
358 //stringification traits
359 template<typename... Args>
360 String& varArgs(Args&&... args) {
361 String temp("", getContext());
362 temp.sprintf(getCString(), std::forward<Args>(args)...);
363 *this = temp;
364 return *this;
365 }
366
367 // CHECK ERROR BITS
368 friend std::istream& operator>>(std::istream& input, String &s) {
369 std::string line;
370 // Still failes gracefully, so whatever...
371 //if(input.good()) {
372 // input.clear();
373 std::getline(input, line);
374 // if(input.fail()) {
375 // Exception::checkThrow(Result::FileRead);
376 // }
377 s = line;
378 //}
379 return input;
380 }
381
382 friend void swap(String& lhs, String& rhs) {
383 void* pTemp = GBL_ALLOCA(sizeof(String));
384 memcpy(pTemp, &lhs, sizeof(String));
385 memcpy(&lhs, &rhs, sizeof(String));
386 memcpy(&rhs, pTemp, sizeof(String));
387 }
388};
389
390
391
392
393
394inline String operator+(const gimbal::StringView& lhs, const gimbal::StringView& rhs) {
395 return String(lhs) += rhs;
396}
397
398inline String operator+(const gimbal::StringView& lhs, const std::string_view& rhs) {
399 return String(lhs) += rhs;
400}
401
402inline String operator"" _gstr(const char* pLiteral, std::size_t length) {
403 // static_assert(length < GBL_STRING_BUFFER_BASE_STACK_SIZE);
404 return String(std::string_view{pLiteral, length});
405}
406
407/* Use variable-length array in C to increase stack size via alloca (but then I guess we gotta store it too)
408 * use template argument in C++ to inherit and increase stack size...
409 *
410 */
411
412// overflow when copying shit into the bitch without enough room on stack when no context is present
413template<Size ExtraStackSize>
414class FlexibleString final: public String {
415public:
416 using FlexibleStringType = FlexibleString<ExtraStackSize>;
417 constexpr static const inline Size ExtraStackBufferSize = ExtraStackSize;
418private:
419 char extraStackBuffer_[ExtraStackSize] = { '0' };
420public:
421
422};
423
424inline StringView::StringView(const gimbal::String& string):
425 StringView(static_cast<const GblStringBuffer&>(string)) {}
426
427}
428
429namespace std {
430 template<gimbal::string_base S>
431 struct hash<S> {
432 std::size_t operator()(const S& str) const {
433 return std::hash<std::string_view>{}(std::string_view(str.getCString()));
434 }
435 };
436}
437
438
439#endif // GIMBAL_STRING_HPP
#define GBL_ALLOCA
#define GBL_ASSERT(...)
uint8_t GblBool
Basic boolean type, standardized to sizeof(char)
Mutable string type optimized for building and writing.