export module Core.ToString; import Core.Math; import Core.Meta; import Core.Types; export import Core.StringFormat; export namespace Core { class StringBase; template concept ToString = requires(const T& t, StringBase& b) { t.toString(b); }; class StringBase { size_t index = 0; size_t capacity = 0; char* buffer = nullptr; public: StringBase() noexcept { } StringBase(char* s, size_t n) noexcept : capacity(n), buffer(s) { } StringBase(StringBase&& other) = default; StringBase(const StringBase& other) = delete; StringBase& operator=(StringBase&& other) = default; StringBase& operator=(const StringBase& other) = delete; operator const char*() const noexcept { return buffer; } void clear() noexcept { index = 0; if(buffer != nullptr) { *buffer = '\0'; } } size_t getCapacity() const noexcept { return index >= capacity ? 0 : capacity - index; } size_t getTotal() const noexcept { return index; } char* getCurrent() const noexcept { return buffer + min(index, capacity); } template size_t addFormat(const char* format, Args&&... args) noexcept { size_t oldIndex = index; ( [&] { StringFormat f; copyFormatUntil(format, f); switcher(args, f); }(), ...); while(*format != '\0') { StringFormat f; copyFormatUntil(format, f); } return index - oldIndex; } template size_t format(const char* format, Args&&... args) noexcept { clear(); return addFormat(format, Core::forward(args)...); } template size_t add(const T& t) noexcept { size_t oldIndex = index; switcher(t); return index - oldIndex; } void print() const noexcept; private: void copyFormatUntil(const char*& format, StringFormat& f) noexcept; #define TO_STRING(type) \ void toString(type t, const StringFormat& format) noexcept 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(bool); template void switcher(const T& t, const StringFormat& format = {}) noexcept { size_t oldIndex = index; if constexpr(Core::Iterable) { switcher("["); auto current = t.begin(); auto end = t.end(); if(current != end) { switcher(*current); ++current; } while(current != end) { switcher(", "); switcher(*current); ++current; } switcher("]"); } else if constexpr(ToString) { t.toString(*this); } else { toString(t, format); } applyPostFormat(oldIndex, index - oldIndex, format); } void addChar(char c) noexcept; void applyPostFormat( size_t startIndex, size_t length, const StringFormat& format) noexcept; void insertSpace(size_t startIndex) noexcept; }; template struct String : public StringBase { char data[N]{}; String() noexcept : StringBase(data, N) { } }; template void print(const char* format, Args&&... args) noexcept { String<256> s; s.addFormat(format, Core::forward(args)...); s.print(); } }