|
|
@@ -1,74 +1,91 @@
|
|
|
-module;
|
|
|
-
|
|
|
export module Core.ToString;
|
|
|
|
|
|
import Core.Math;
|
|
|
import Core.Meta;
|
|
|
import Core.Types;
|
|
|
|
|
|
+export import Core.StringFormat;
|
|
|
+
|
|
|
+#define TO_STRING(type) \
|
|
|
+ size_t toString(type t, char* s, size_t n, const StringFormat& format = {})
|
|
|
+
|
|
|
export namespace Core {
|
|
|
- size_t toString(signed char v, char* s, size_t n);
|
|
|
- size_t toString(char v, char* s, size_t n);
|
|
|
- size_t toString(short v, char* s, size_t n);
|
|
|
- size_t toString(int v, char* s, size_t n);
|
|
|
- size_t toString(long v, char* s, size_t n);
|
|
|
- size_t toString(long long v, char* s, size_t n);
|
|
|
- size_t toString(unsigned char v, char* s, size_t n);
|
|
|
- size_t toString(unsigned short v, char* s, size_t n);
|
|
|
- size_t toString(unsigned int v, char* s, size_t n);
|
|
|
- size_t toString(unsigned long v, char* s, size_t n);
|
|
|
- size_t toString(unsigned long long v, char* s, size_t n);
|
|
|
- size_t toString(float v, char* s, size_t n);
|
|
|
- size_t toString(double v, char* s, size_t n);
|
|
|
- size_t toString(const char* v, char* s, size_t n);
|
|
|
- size_t toString(char* v, char* s, size_t n);
|
|
|
- size_t toString(const unsigned char* v, char* s, size_t n);
|
|
|
- size_t toString(unsigned char* v, char* s, size_t n);
|
|
|
- size_t toString(bool v, char* s, size_t n);
|
|
|
+ TO_STRING(signed char);
|
|
|
+ TO_STRING(char);
|
|
|
+ TO_STRING(short);
|
|
|
+ TO_STRING(int);
|
|
|
+ TO_STRING(long);
|
|
|
+ TO_STRING(long long);
|
|
|
+ TO_STRING(unsigned char);
|
|
|
+ TO_STRING(unsigned short);
|
|
|
+ TO_STRING(unsigned int);
|
|
|
+ TO_STRING(unsigned long);
|
|
|
+ TO_STRING(unsigned long long);
|
|
|
+ TO_STRING(float);
|
|
|
+ TO_STRING(double);
|
|
|
+ TO_STRING(const char*);
|
|
|
+ TO_STRING(const unsigned char*);
|
|
|
+ TO_STRING(unsigned char*);
|
|
|
+ TO_STRING(bool);
|
|
|
|
|
|
template<typename T>
|
|
|
- size_t toString(const T& t, char* s, size_t n);
|
|
|
+ void addString(
|
|
|
+ const T& t, char*& s, size_t& n, size_t& total,
|
|
|
+ const StringFormat& format = {});
|
|
|
+
|
|
|
+ template<Core::Iterable T>
|
|
|
+ size_t toString(
|
|
|
+ const T& t, char* s, size_t n, const StringFormat& format = {}) {
|
|
|
+ (void)format;
|
|
|
+ size_t total = 0;
|
|
|
+ addString("[", s, n, total);
|
|
|
+ auto current = t.begin();
|
|
|
+ auto end = t.end();
|
|
|
+ if(current != end) {
|
|
|
+ addString(*current, s, n, total);
|
|
|
+ ++current;
|
|
|
+ }
|
|
|
+ while(current != end) {
|
|
|
+ addString(", ", s, n, total);
|
|
|
+ addString(*current, s, n, total);
|
|
|
+ ++current;
|
|
|
+ }
|
|
|
+ addString("]", s, n, total);
|
|
|
+ return total;
|
|
|
+ }
|
|
|
|
|
|
template<typename T>
|
|
|
- void addString(const T& t, char*& s, size_t& n, size_t& total) {
|
|
|
- size_t w = toString(t, s, n);
|
|
|
+ concept ToString =
|
|
|
+ requires(const T& t, char* s, size_t n) { t.toString(s, n); };
|
|
|
+
|
|
|
+ template<ToString T>
|
|
|
+ size_t toString(
|
|
|
+ const T& t, char* s, size_t n, const StringFormat& format = {}) {
|
|
|
+ (void)format;
|
|
|
+ return t.toString(s, n);
|
|
|
+ }
|
|
|
+
|
|
|
+ template<typename T>
|
|
|
+ void addString(
|
|
|
+ const T& t, char*& s, size_t& n, size_t& total,
|
|
|
+ const StringFormat& format) {
|
|
|
+ size_t w = toString(t, s, n, format);
|
|
|
total += w;
|
|
|
w = Core::min(n, w);
|
|
|
s += w;
|
|
|
n -= w;
|
|
|
}
|
|
|
|
|
|
- template<typename T>
|
|
|
- size_t toString(const T& t, char* s, size_t n) {
|
|
|
- if constexpr(Core::Iterable<T>) {
|
|
|
- size_t total = 0;
|
|
|
- addString("[", s, n, total);
|
|
|
- auto current = t.begin();
|
|
|
- auto end = t.end();
|
|
|
- if(current != end) {
|
|
|
- addString(*current, s, n, total);
|
|
|
- ++current;
|
|
|
- }
|
|
|
- while(current != end) {
|
|
|
- addString(", ", s, n, total);
|
|
|
- addString(*current, s, n, total);
|
|
|
- ++current;
|
|
|
- }
|
|
|
- addString("]", s, n, total);
|
|
|
- return total;
|
|
|
- } else {
|
|
|
- return t.toString(s, n);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- size_t copyFormatUntil(const char*& format, char*& s, size_t& n);
|
|
|
+ size_t copyFormatUntil(
|
|
|
+ const char*& format, char*& s, size_t& n, StringFormat& f);
|
|
|
|
|
|
template<typename T, typename... Args>
|
|
|
void formatR(
|
|
|
const char*& format, char*& s, size_t& n, size_t& total, const T& t,
|
|
|
Args&&... args) {
|
|
|
- total += copyFormatUntil(format, s, n);
|
|
|
- addString(t, s, n, total);
|
|
|
+ StringFormat f;
|
|
|
+ total += copyFormatUntil(format, s, n, f);
|
|
|
+ addString(t, s, n, total, f);
|
|
|
if constexpr(sizeof...(args) > 0) {
|
|
|
formatR(format, s, n, total, Core::forward<Args>(args)...);
|
|
|
}
|
|
|
@@ -76,11 +93,60 @@ export namespace Core {
|
|
|
|
|
|
template<typename... Args>
|
|
|
size_t formatBuffer(char* s, size_t n, const char* format, Args&&... args) {
|
|
|
+ StringFormat f;
|
|
|
+ size_t total = 0;
|
|
|
if constexpr(sizeof...(args) > 0) {
|
|
|
- size_t total = 0;
|
|
|
formatR(format, s, n, total, Core::forward<Args>(args)...);
|
|
|
- return total + toString(format, s, n);
|
|
|
}
|
|
|
- return copyFormatUntil(format, s, n);
|
|
|
+ return total + copyFormatUntil(format, s, n, f);
|
|
|
+ }
|
|
|
+
|
|
|
+ struct StringBase {
|
|
|
+ size_t index = 0;
|
|
|
+ size_t capacity = 0;
|
|
|
+ char* buffer = nullptr;
|
|
|
+
|
|
|
+ StringBase() {
|
|
|
+ }
|
|
|
+
|
|
|
+ StringBase(StringBase&& other) = default;
|
|
|
+ StringBase(const StringBase& other) = delete;
|
|
|
+ StringBase& operator=(StringBase&& other) = default;
|
|
|
+ StringBase& operator=(const StringBase& other) = delete;
|
|
|
+
|
|
|
+ template<typename... Args>
|
|
|
+ size_t format(const char* format, Args&&... args) {
|
|
|
+ size_t total = formatBuffer(
|
|
|
+ buffer + index, capacity - index, format,
|
|
|
+ Core::forward<Args>(args)...);
|
|
|
+ index = Core::min(index + total, capacity);
|
|
|
+ return total;
|
|
|
+ }
|
|
|
+
|
|
|
+ template<typename T>
|
|
|
+ size_t add(const T& t) {
|
|
|
+ size_t total = toString(t, buffer + index, capacity - index);
|
|
|
+ index = Core::min(index + total, capacity);
|
|
|
+ return total;
|
|
|
+ }
|
|
|
+
|
|
|
+ void print();
|
|
|
+ };
|
|
|
+
|
|
|
+ template<size_t N>
|
|
|
+ struct String : public StringBase {
|
|
|
+ char data[N]{};
|
|
|
+
|
|
|
+ String() {
|
|
|
+ buffer = data;
|
|
|
+ capacity = N;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ template<typename... Args>
|
|
|
+ void print(const char* format, Args&&... args) {
|
|
|
+ String<256> s;
|
|
|
+ s.format(format, Core::forward<Args>(args)...);
|
|
|
+ s.print();
|
|
|
}
|
|
|
}
|