AUI Framework  develop
Cross-platform base for C++ UI apps
Loading...
Searching...
No Matches
AString.h
1/*
2 * AUI Framework - Declarative UI toolkit for modern C++20
3 * Copyright (C) 2020-2024 Alex2772 and Contributors
4 *
5 * SPDX-License-Identifier: MPL-2.0
6 *
7 * This Source Code Form is subject to the terms of the Mozilla Public
8 * License, v. 2.0. If a copy of the MPL was not distributed with this
9 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 */
11
12#pragma once
13
14#include <string>
15#include <iostream>
16#include "AUI/Core.h"
17#include "AUI/Traits/values.h"
18#include <AUI/Common/ASet.h>
19#include <optional>
20#include <AUI/Common/AOptional.h>
21#include <fmt/core.h>
22
23class API_AUI_CORE AStringVector;
24class API_AUI_CORE AByteBuffer;
25class API_AUI_CORE AByteBufferView;
26
36class API_AUI_CORE AString: std::u16string
37{
38private:
39 friend struct std::hash<AString>;
40 using super = std::u16string;
41
42public:
43
44 using iterator = super::iterator;
45 using value_type = super::value_type;
46 using const_iterator = super::const_iterator;
47 using reverse_iterator = super::reverse_iterator;
48 using const_reverse_iterator = super::const_reverse_iterator;
49 auto constexpr static NPOS = super::npos;
50
51
52 AString(AString&& other) noexcept
53 : std::u16string(static_cast<basic_string&&>(other))
54 {
55 }
56
60 AString(const basic_string& other) noexcept
61 : basic_string<char16_t>(other)
62 {
63 }
64
68 AString(const std::string& utf8) noexcept;
69
70 AString(const AString& other) noexcept
71 : super(other.c_str())
72 {
73 }
74
75 AString(const basic_string& rhs, const std::allocator<char16_t>& allocator) noexcept
76 : basic_string<char16_t>(rhs, allocator)
77 {
78 }
79
80 template <class Iterator>
81 AString(Iterator first, Iterator last) noexcept : super(first, last) {}
82
83 AString() noexcept
84 {
85 }
86
87 AString(char16_t c) noexcept : super(&c, &c + 1)
88 {
89
90 }
91
95 AString(const char* utf8) noexcept;
96
100 AString(std::string_view utf8) noexcept;
101
102 explicit AString(const std::allocator<char16_t>& allocator) noexcept
103 : basic_string<char16_t>(allocator)
104 {
105 }
106
107 AString(const basic_string& rhs, size_type offset, const std::allocator<char16_t>& allocator) noexcept
108 : basic_string<char16_t>(rhs, offset, allocator)
109 {
110 }
111
112 AString(const basic_string& rhs, size_type offset, size_type count, const std::allocator<char16_t>& allocator) noexcept
113 : basic_string<char16_t>(rhs, offset, count, allocator)
114 {
115 }
116
117 AString(const char16_t* cStyleString, size_type count) noexcept
118 : basic_string<char16_t>(cStyleString, count)
119 {
120 }
121
122 AString(const char16_t* cStyleString, size_type count, const std::allocator<char16_t>& allocator) noexcept
123 : basic_string<char16_t>(cStyleString, count, allocator)
124 {
125 }
126
127 AString(const char16_t* cStyleString) noexcept
128 : basic_string<char16_t>(cStyleString)
129 {
130 }
131
132 AString(const char16_t* cStyleString, const std::allocator<char16_t>& allocator) noexcept
133 : basic_string<char16_t>(cStyleString, allocator)
134 {
135 }
136
137 AString(size_type count, char16_t _Ch) noexcept
138 : basic_string<char16_t>(count, _Ch)
139 {
140 }
141
142 AString(size_type count, char16_t _Ch, const std::allocator<char16_t>& allocator) noexcept
143 : basic_string<char16_t>(count, _Ch, allocator)
144 {
145 }
146
147 AString(basic_string&& rhs) noexcept
148 : basic_string<char16_t>(std::move(rhs))
149 {
150 }
151
152 AString(basic_string&& rhs, const std::allocator<char16_t>& allocator) noexcept
153 : basic_string<char16_t>(std::move(rhs), allocator)
154 {
155 }
156
157 AString(std::initializer_list<char16_t> _Ilist) noexcept
158 : basic_string<char16_t>(_Ilist)
159 {
160 }
161
162 ~AString() = default;
163
164
165 void push_back(char16_t c) noexcept
166 {
167 super::push_back(c);
168 }
169 void pop_back() noexcept
170 {
171 super::pop_back();
172 }
173
174 AString uppercase() const;
175 AString lowercase() const;
176
177 bool startsWith(const AString& other) const noexcept
178 {
179 return rfind(other, 0) == 0;
180 }
181 bool startsWith(char16_t c) const noexcept
182 {
183 return rfind(c, 0) == 0;
184 }
185 bool endsWith(const AString& other) const noexcept
186 {
187 if (length() < other.length())
188 {
189 return false;
190 }
191 size_t offset = length() - other.length();
192 return super::find(other, offset) == offset;
193 }
194 bool endsWith(char16_t c) const noexcept
195 {
196 size_t offset = length() - 1;
197 return super::find(c, offset) == offset;
198 }
199
200 AStringVector split(char16_t c) const noexcept;
201
202 size_type find(char c, size_type offset = 0) const noexcept
203 {
204 return super::find(c, offset);
205 }
206 size_type find(char16_t c, size_type offset = 0) const noexcept
207 {
208 return super::find(c, offset);
209 }
210 size_type find(const AString& str, size_type offset = 0) const noexcept
211 {
212 return super::find(str, offset);
213 }
214 size_type rfind(char c, size_type offset = NPOS) const noexcept
215 {
216 return super::rfind(c, offset);
217 }
218 size_type rfind(char16_t c, size_type offset = NPOS) const noexcept
219 {
220 return super::rfind(c, offset);
221 }
222 size_type rfind(const AString& str, size_type offset = NPOS) const noexcept
223 {
224 return super::rfind(str, offset);
225 }
226 size_type length() const noexcept
227 {
228 return super::length();
229 }
230 AString trimLeft(char16_t symbol = ' ') const noexcept;
231 AString trimRight(char16_t symbol = ' ') const noexcept;
232
233 AString trim(char16_t symbol = ' ') const noexcept
234 {
235 return trimRight(symbol).trimLeft(symbol);
236 }
237
238 void reserve(size_t s)
239 {
240 super::reserve(s);
241 }
242 void resize(size_t s)
243 {
244 super::resize(s);
245 }
246
247 AString restrictLength(size_t s, const AString& stringAtEnd = "...") const;
248
249 char16_t* data() noexcept
250 {
251 return super::data();
252 }
253
254 const char16_t* data() const noexcept
255 {
256 return super::data();
257 }
258 AString& replaceAll(const AString& from, const AString& to);
259 [[nodiscard]] AString replacedAll(const AString& from, const AString& to) const;
260 [[nodiscard]] inline AString replacedAll(char16_t from, char16_t to) const noexcept {
261 AString copy;
262 copy.reserve(length() + 10);
263 for (auto c : *this) {
264 if (c == from) {
265 copy << to;
266 } else {
267 copy << c;
268 }
269 }
270 return copy;
271 }
272 [[nodiscard]] inline AString replacedAll(const ASet<char16_t>& from, char16_t to) const noexcept {
273 AString copy;
274 copy.reserve(length() + 10);
275 for (auto c : *this) {
276 if (from.contains(c)) {
277 copy << to;
278 } else {
279 copy << c;
280 }
281 }
282 return copy;
283 }
284 AString& replaceAll(char16_t from, char16_t to) noexcept;
285
286
292 template<typename OtherContainer>
293 void insertAll(const OtherContainer& c) noexcept {
294 super::insert(super::end(), c.begin(), c.end());
295 }
296
303 [[nodiscard]]
304 AOptional<float> toFloat() const noexcept;
305
312 [[nodiscard]]
313 AOptional<double> toDouble() const noexcept;
314
321 [[nodiscard]]
322 double toDoubleOrException() const noexcept {
323 return toDouble().valueOrException(fmt::format("bad double: {}", toStdString()).c_str());
324 }
325
333 [[nodiscard]]
334 AOptional<int> toInt() const noexcept;
335
343 [[nodiscard]]
344 int toIntOrException() const {
345 return toInt().valueOrException(fmt::format("bad int: {}", toStdString()).c_str());
346 }
347
355 [[nodiscard]]
356 AOptional<int64_t> toLongInt() const noexcept;
357
365 [[nodiscard]]
366 int64_t toLongIntOrException() const {
367 return toLongInt().valueOrException(fmt::format("bad to number conversion: {}", toStdString()).c_str());
368 }
369
377 [[nodiscard]]
378 AOptional<unsigned> toUInt() const noexcept;
379
387 [[nodiscard]]
388 unsigned toUIntOrException() const {
389 return toUInt().valueOrException(fmt::format("bad to number conversion: {}", toStdString()).c_str());
390 }
391
396 [[nodiscard]]
397 bool toBool() const noexcept {
398 return *this == "true";
399 }
400
401 [[nodiscard]]
402 bool contains(char16_t c) const noexcept
403 {
404 return find(c) != npos;
405 }
406 [[nodiscard]]
407 bool contains(const AString& other) const noexcept
408 {
409 return find(other) != npos;
410 }
411
412 static AString fromLatin1(const AByteBuffer& buffer);
413 static AString fromUtf8(const AByteBufferView& buffer);
414 static AString fromUtf8(const char* buffer, size_t length);
415 static AString fromLatin1(const char* buffer);
416
417 static AString numberHex(int i) noexcept;
418
419 template<typename T, std::enable_if_t<std::is_integral_v<std::decay_t<T>> || std::is_floating_point_v<std::decay_t<T>>, int> = 0>
420 static AString number(T i) noexcept {
421 if constexpr (std::is_same_v<bool, std::decay_t<T>>) {
422 if (i)
423 return "true";
424 return "false";
425 } else {
426 auto v = std::to_string(i);
427 if constexpr (std::is_floating_point_v<T>) {
428 // remove trailing zeros
429 v.erase(v.find_last_not_of('0') + 1, std::u16string::npos);
430 v.erase(v.find_last_not_of('.') + 1, std::u16string::npos);
431 }
432 return v;
433 }
434 }
435
436 static constexpr auto TO_NUMBER_BASE_BIN = 2;
437 static constexpr auto TO_NUMBER_BASE_OCT = 8;
438 static constexpr auto TO_NUMBER_BASE_DEC = 10;
439 static constexpr auto TO_NUMBER_BASE_HEX = 16;
440
441
446 AOptional<int> toNumber(aui::ranged_number<int, 2, 36> base = TO_NUMBER_BASE_DEC) const noexcept;
447
452 int toNumberOrException(aui::ranged_number<int, 2, 36> base = TO_NUMBER_BASE_DEC) const {
453 return toNumber(base).valueOrException(fmt::format("bad to number conversion: {}", toStdString()).c_str());
454 }
455
456
460 std::string toStdString() const noexcept;
461
462 void resizeToNullTerminator();
463
464 iterator erase(const_iterator begin, const_iterator end) noexcept
465 {
466 return super::erase(begin, end);
467 }
468 iterator erase(const_iterator begin) noexcept
469 {
470 return super::erase(begin);
471 }
472
473 AString& erase(size_type offset) noexcept
474 {
475 super::erase(offset);
476 return *this;
477 }
478 AString& erase(size_type offset, size_type count) noexcept
479 {
480 super::erase(offset, count);
481 return *this;
482 }
483
484 AByteBuffer toUtf8() const noexcept;
485
486 void removeAt(unsigned at) noexcept
487 {
488 AUI_ASSERT(at <= length());
489 erase(begin() + at);
490 }
491 AString excessSpacesRemoved() const noexcept;
492
493 iterator insert(size_type at, char16_t c) noexcept
494 {
495 AUI_ASSERT(at <= length());
496 return super::insert(begin() + at, 1, c);
497 }
498 iterator insert(size_type at, const AString& c) noexcept
499 {
500 AUI_ASSERT(at <= length());
501 return super::insert(begin() + at, c.begin(), c.end());
502 }
503
504 template<typename Iterator>
505 iterator insert(const_iterator at, Iterator begin, Iterator end) noexcept
506 {
507 AUI_ASSERT(std::distance(super::cbegin(), at) <= length());
508 return super::insert(at, begin, end);
509 }
510
511 AString& operator<<(char c) noexcept
512 {
513 append(1, c);
514 return *this;
515 }
516 AString& operator<<(char16_t c) noexcept
517 {
518 append(1, c);
519 return *this;
520 }
521
522 inline ::AString& operator+=(const AString& str) noexcept
523 {
524 append(str);
525 return *this;
526 }
527 inline ::AString& operator+=(const char* str) noexcept
528 {
529 *this += AString(str);
530 return *this;
531 }
532
533 [[nodiscard]] bool empty() const noexcept {
534 return super::empty();
535 }
536 [[nodiscard]] size_type size() const noexcept {
537 return super::size();
538 }
539 char16_t operator[](size_type index) const
540 {
541 return super::at(index);
542 }
543 char16_t& operator[](size_type index)
544 {
545 return super::at(index);
546 }
547 bool operator<(const AString& other) const noexcept
548 {
549 return compare(other) < 0;
550 }
551
552 void clear() noexcept
553 {
554 super::clear();
555 }
556
557 char16_t& front() noexcept
558 {
559 return super::front();
560 }
561 char16_t& back() noexcept
562 {
563 return super::back();
564 }
565 const char16_t& front() const noexcept
566 {
567 return super::front();
568 }
569 const char16_t& back() const noexcept
570 {
571 return super::back();
572 }
573 char16_t& first() noexcept
574 {
575 return super::front();
576 }
577 char16_t& last() noexcept
578 {
579 return super::back();
580 }
581 const char16_t& first() const noexcept
582 {
583 return super::front();
584 }
585 const char16_t& last() const noexcept
586 {
587 return super::back();
588 }
589
590 const char16_t* c_str() const
591 {
592 return super::c_str();
593 }
594
595 iterator begin() noexcept
596 {
597 return super::begin();
598 }
599 iterator end() noexcept
600 {
601 return super::end();
602 }
603
604 const_iterator begin() const noexcept
605 {
606 return super::begin();
607 }
608 const_iterator end() const noexcept
609 {
610 return super::end();
611 }
612
613 reverse_iterator rbegin() noexcept
614 {
615 return super::rbegin();
616 }
617 reverse_iterator rend() noexcept
618 {
619 return super::rend();
620 }
621
622 const_reverse_iterator rbegin() const noexcept
623 {
624 return super::rbegin();
625 }
626 const_reverse_iterator rend() const noexcept
627 {
628 return super::rend();
629 }
630
631 AString& append(const AString& s) noexcept
632 {
633 super::append(s);
634 return *this;
635 }
636
637 AString& append(size_t count, char16_t ch) noexcept
638 {
639 super::append(count, ch);
640 return *this;
641 }
642
643 const AString& operator=(const AString& value) noexcept
644 {
645 super::operator=(value);
646 return *this;
647 }
648
649 const AString& operator=(AString&& value) noexcept
650 {
651 super::operator=(value);
652 return *this;
653 }
654
655 bool operator==(const AString& other) const noexcept
656 {
657 if (size() != other.size()) {
658 return false;
659 }
660 return std::memcmp(data(), other.data(), sizeInBytes()) == 0;
661 }
662 bool operator==(const char16_t* other) const noexcept
663 {
664 auto it = begin();
665 for (; it != end(); ++it, ++other) {
666 if (*it != *other) {
667 return false;
668 }
669 if (*other == '\0') {
670 return false;
671 }
672 }
673 return *other == '\0';
674 }
675
676 [[nodiscard]]
677 size_t sizeInBytes() const noexcept {
678 return size() * sizeof(super::value_type);
679 }
680
681 bool operator!=(const AString& other) const noexcept
682 {
683 return !operator==(other);
684 }
685 bool operator!=(const char16_t* other) const noexcept
686 {
687 return !operator==(other);
688 }
689
690 bool operator==(const char* other) const noexcept
691 {
692 return *this == AString(other);
693 }
694
695 bool operator!=(const char* other) const noexcept
696 {
697 return *this != AString(other);
698 }
699
700 template<typename... Args>
701 inline AString format(Args&&... args) const;
702
703 AString processEscapes() const;
704
705 AString& removeAll(char16_t c) noexcept {
706 erase(std::remove(begin(), end(), c));
707 return *this;
708 }
709
710 [[nodiscard]]
711 AString substr(std::size_t offset, std::size_t count = npos) const {
712 return super::substr(offset, count);
713 }
714
715private:
719 template<typename T>
720 AOptional<T> toNumberImpl() const noexcept;
721};
722
723inline AString operator+(const AString& l, const AString& r) noexcept
724{
725 auto x = l;
726 x.append(r);
727 return x;
728}
729inline AString operator+(const AString& l, char16_t r) noexcept
730{
731 auto x = l;
732 x.append(r);
733 return x;
734}
735inline AString operator+(const AString& one, const char* other) noexcept
736{
737 return one + AString(other);
738}
739
740inline AString operator+(const char* other, const AString& one) noexcept {
741 return AString(other) + one;
742}
743
744inline AString operator+(char lhs, const AString& cs) noexcept
745{
746 AString s(lhs);
747 s += cs;
748 return s;
749}
750
751inline AString operator""_as(const char* str, size_t len)
752{
753 return {str};
754}
755
756inline std::ostream& operator<<(std::ostream& o, const AString& s)
757{
758 o << s.toStdString();
759 return o;
760}
761
762template<>
763struct std::hash<AString>
764{
765 size_t operator()(const AString& t) const
766 {
767 return std::hash<std::u16string>()(t);
768 }
769};
770
771#if AUI_PLATFORM_WIN
772namespace aui::win32 {
773 /*
774 * On Windows, char16_t == wchar_t. WinAPI interfaces use wchar_t widely, so we have some handy functions to
775 * convert AString to wchar_t* and back.
776 */
777
782 inline const wchar_t* toWchar(const AString& string) {
783 // NOLINTNEXTLINE(*-pro-type-reinterpret-cast)
784 return reinterpret_cast<const wchar_t *const>(string.data());
785 }
786
791 inline wchar_t* toWchar(AString& string) {
792 // NOLINTNEXTLINE(*-pro-type-reinterpret-cast)
793 return reinterpret_cast<wchar_t*>(string.data());
794 }
795
800 inline std::wstring_view toWcharView(const AString& string) {
801 return {toWchar(string), string.length() };
802 }
803
808 inline AString fromWchar(std::wstring_view string) {
809 // NOLINTNEXTLINE(*-pro-type-reinterpret-cast)
810 return {reinterpret_cast<const char16_t *>(string.data()), string.size()};
811 }
812}
813#endif
814
815template <> struct fmt::detail::is_string<AString>: std::false_type {};
816
817template <> struct fmt::formatter<AString>: fmt::formatter<std::string> {
818 auto format(const AString& s, format_context& ctx) const {
819 return fmt::formatter<std::string>::format(s.toStdString(), ctx);
820 }
821};
822
823
824// gtest printer for AString
825inline void PrintTo(const AString& s, std::ostream* stream) {
826 *stream << s.toStdString();
827}
Acts like std::string_view but for AByteBuffer.
Definition AByteBufferView.h:24
std::vector-like growing array for byte storage.
Definition AByteBuffer.h:31
Utility wrapper implementing the stack-allocated (fast) optional idiom.
Definition AOptional.h:32
An AVector with string-related functions.
Definition AStringVector.h:22
Represents a Unicode character string.
Definition AString.h:37
int toIntOrException() const
Converts the string to int value.
Definition AString.h:344
int64_t toLongIntOrException() const
Converts the string to int value.
Definition AString.h:366
AString(const basic_string &other) noexcept
Definition AString.h:60
bool toBool() const noexcept
Converts the string to boolean value.
Definition AString.h:397
void insertAll(const OtherContainer &c) noexcept
Inserts all values of the specified container to the end.
Definition AString.h:293
AOptional< int > toInt() const noexcept
Converts the string to int value.
Definition AString.cpp:1304
AOptional< int64_t > toLongInt() const noexcept
Converts the string to int value.
Definition AString.cpp:1308
std::string toStdString() const noexcept
Definition AString.cpp:338
AOptional< double > toDouble() const noexcept
Converts the string to a double number.
Definition AString.cpp:1316
AOptional< int > toNumber(aui::ranged_number< int, 2, 36 > base=TO_NUMBER_BASE_DEC) const noexcept
Returns the string converted to an int using base. Returns std::nullopt if the conversion fails.
Definition AString.cpp:310
double toDoubleOrException() const noexcept
Converts the string to a double number.
Definition AString.h:322
unsigned toUIntOrException() const
Converts the string to int value.
Definition AString.h:388
int toNumberOrException(aui::ranged_number< int, 2, 36 > base=TO_NUMBER_BASE_DEC) const
Returns the string converted to an int using base. Throws an exception if the conversion fails.
Definition AString.h:452
AOptional< unsigned > toUInt() const noexcept
Converts the string to int value.
Definition AString.cpp:1312
class_of c
Selects views that are of the specified classes.
Definition class_of.h:84
bool contains(const Container &c, const typename Container::const_reference value) noexcept
Definition containers.h:124
#define AUI_ASSERT(condition)
Asserts that the passed condition evaluates to true.
Definition Assert.h:55
std::wstring_view toWcharView(const AString &string)
AString to wchar_t string view.
Definition AString.h:800
const wchar_t * toWchar(const AString &string)
AString to const wchar_t*.
Definition AString.h:782
AString fromWchar(std::wstring_view string)
wchar_t string view to AString.
Definition AString.h:808
Clamps the possible values for a number to the specified range: [min;max].
Definition values.h:456