ToString.cppm 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. export module Core.ToString;
  2. import Core.Math;
  3. import Core.Meta;
  4. import Core.Types;
  5. export import Core.StringFormat;
  6. export namespace Core {
  7. class StringBase;
  8. template<typename T>
  9. concept ToString = requires(const T& t, StringBase& b) { t.toString(b); };
  10. class StringBase {
  11. size_t index = 0;
  12. size_t capacity = 0;
  13. char* buffer = nullptr;
  14. public:
  15. StringBase() noexcept {
  16. }
  17. StringBase(char* s, size_t n) noexcept : capacity(n), buffer(s) {
  18. }
  19. StringBase(StringBase&& other) = default;
  20. StringBase(const StringBase& other) = delete;
  21. StringBase& operator=(StringBase&& other) = default;
  22. StringBase& operator=(const StringBase& other) = delete;
  23. operator const char*() const noexcept {
  24. return buffer;
  25. }
  26. void clear() noexcept {
  27. index = 0;
  28. if(buffer != nullptr) {
  29. *buffer = '\0';
  30. }
  31. }
  32. size_t getCapacity() const noexcept {
  33. return index >= capacity ? 0 : capacity - index;
  34. }
  35. size_t getTotal() const noexcept {
  36. return index;
  37. }
  38. char* getCurrent() const noexcept {
  39. return buffer + min(index, capacity);
  40. }
  41. template<typename... Args>
  42. size_t addFormat(const char* format, Args&&... args) noexcept {
  43. size_t oldIndex = index;
  44. (
  45. [&] {
  46. StringFormat f;
  47. copyFormatUntil(format, f);
  48. switcher(args, f);
  49. }(),
  50. ...);
  51. while(*format != '\0') {
  52. StringFormat f;
  53. copyFormatUntil(format, f);
  54. }
  55. return index - oldIndex;
  56. }
  57. template<typename... Args>
  58. size_t format(const char* format, Args&&... args) noexcept {
  59. clear();
  60. return addFormat<Args...>(format, Core::forward<Args>(args)...);
  61. }
  62. template<typename T>
  63. size_t add(const T& t) noexcept {
  64. size_t oldIndex = index;
  65. switcher(t);
  66. return index - oldIndex;
  67. }
  68. void print() const noexcept;
  69. private:
  70. void copyFormatUntil(const char*& format, StringFormat& f) noexcept;
  71. #define TO_STRING(type) \
  72. void toString(type t, const StringFormat& format) noexcept
  73. TO_STRING(signed char);
  74. TO_STRING(char);
  75. TO_STRING(short);
  76. TO_STRING(int);
  77. TO_STRING(long);
  78. TO_STRING(long long);
  79. TO_STRING(unsigned char);
  80. TO_STRING(unsigned short);
  81. TO_STRING(unsigned int);
  82. TO_STRING(unsigned long);
  83. TO_STRING(unsigned long long);
  84. TO_STRING(float);
  85. TO_STRING(double);
  86. TO_STRING(const char*);
  87. TO_STRING(const unsigned char*);
  88. TO_STRING(unsigned char*);
  89. TO_STRING(bool);
  90. template<typename T>
  91. void switcher(const T& t, const StringFormat& format = {}) noexcept {
  92. size_t oldIndex = index;
  93. if constexpr(Core::Iterable<T>) {
  94. switcher("[");
  95. auto current = t.begin();
  96. auto end = t.end();
  97. if(current != end) {
  98. switcher(*current);
  99. ++current;
  100. }
  101. while(current != end) {
  102. switcher(", ");
  103. switcher(*current);
  104. ++current;
  105. }
  106. switcher("]");
  107. } else if constexpr(ToString<T>) {
  108. t.toString(*this);
  109. } else {
  110. toString(t, format);
  111. }
  112. applyPostFormat(oldIndex, index - oldIndex, format);
  113. }
  114. void applyPostFormat(
  115. size_t startIndex, size_t length,
  116. const StringFormat& format) noexcept;
  117. void insertSpace(size_t startIndex) noexcept;
  118. };
  119. template<size_t N>
  120. struct String : public StringBase {
  121. char data[N]{};
  122. String() noexcept : StringBase(data, N) {
  123. }
  124. };
  125. template<typename... Args>
  126. void print(const char* format, Args&&... args) noexcept {
  127. String<256> s;
  128. s.addFormat(format, Core::forward<Args>(args)...);
  129. s.print();
  130. }
  131. }