You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

228 lines
7.6 KiB

10 months ago
  1. // Copyright Toru Niina 2017.
  2. // Distributed under the MIT License.
  3. #ifndef TOML11_STRING_HPP
  4. #define TOML11_STRING_HPP
  5. #include "version.hpp"
  6. #include <cstdint>
  7. #include <algorithm>
  8. #include <string>
  9. #if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
  10. #if __has_include(<string_view>)
  11. #define TOML11_USING_STRING_VIEW 1
  12. #include <string_view>
  13. #endif
  14. #endif
  15. namespace toml
  16. {
  17. enum class string_t : std::uint8_t
  18. {
  19. basic = 0,
  20. literal = 1,
  21. };
  22. struct string
  23. {
  24. string() = default;
  25. ~string() = default;
  26. string(const string& s) = default;
  27. string(string&& s) = default;
  28. string& operator=(const string& s) = default;
  29. string& operator=(string&& s) = default;
  30. string(const std::string& s): kind(string_t::basic), str(s){}
  31. string(const std::string& s, string_t k): kind(k), str(s){}
  32. string(const char* s): kind(string_t::basic), str(s){}
  33. string(const char* s, string_t k): kind(k), str(s){}
  34. string(std::string&& s): kind(string_t::basic), str(std::move(s)){}
  35. string(std::string&& s, string_t k): kind(k), str(std::move(s)){}
  36. string& operator=(const std::string& s)
  37. {kind = string_t::basic; str = s; return *this;}
  38. string& operator=(std::string&& s)
  39. {kind = string_t::basic; str = std::move(s); return *this;}
  40. operator std::string& () & noexcept {return str;}
  41. operator std::string const& () const& noexcept {return str;}
  42. operator std::string&& () && noexcept {return std::move(str);}
  43. string& operator+=(const char* rhs) {str += rhs; return *this;}
  44. string& operator+=(const char rhs) {str += rhs; return *this;}
  45. string& operator+=(const std::string& rhs) {str += rhs; return *this;}
  46. string& operator+=(const string& rhs) {str += rhs.str; return *this;}
  47. #if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
  48. explicit string(std::string_view s): kind(string_t::basic), str(s){}
  49. string(std::string_view s, string_t k): kind(k), str(s){}
  50. string& operator=(std::string_view s)
  51. {kind = string_t::basic; str = s; return *this;}
  52. explicit operator std::string_view() const noexcept
  53. {return std::string_view(str);}
  54. string& operator+=(const std::string_view& rhs) {str += rhs; return *this;}
  55. #endif
  56. string_t kind;
  57. std::string str;
  58. };
  59. inline bool operator==(const string& lhs, const string& rhs)
  60. {
  61. return lhs.kind == rhs.kind && lhs.str == rhs.str;
  62. }
  63. inline bool operator!=(const string& lhs, const string& rhs)
  64. {
  65. return !(lhs == rhs);
  66. }
  67. inline bool operator<(const string& lhs, const string& rhs)
  68. {
  69. return (lhs.kind == rhs.kind) ? (lhs.str < rhs.str) : (lhs.kind < rhs.kind);
  70. }
  71. inline bool operator>(const string& lhs, const string& rhs)
  72. {
  73. return rhs < lhs;
  74. }
  75. inline bool operator<=(const string& lhs, const string& rhs)
  76. {
  77. return !(rhs < lhs);
  78. }
  79. inline bool operator>=(const string& lhs, const string& rhs)
  80. {
  81. return !(lhs < rhs);
  82. }
  83. inline bool
  84. operator==(const string& lhs, const std::string& rhs) {return lhs.str == rhs;}
  85. inline bool
  86. operator!=(const string& lhs, const std::string& rhs) {return lhs.str != rhs;}
  87. inline bool
  88. operator< (const string& lhs, const std::string& rhs) {return lhs.str < rhs;}
  89. inline bool
  90. operator> (const string& lhs, const std::string& rhs) {return lhs.str > rhs;}
  91. inline bool
  92. operator<=(const string& lhs, const std::string& rhs) {return lhs.str <= rhs;}
  93. inline bool
  94. operator>=(const string& lhs, const std::string& rhs) {return lhs.str >= rhs;}
  95. inline bool
  96. operator==(const std::string& lhs, const string& rhs) {return lhs == rhs.str;}
  97. inline bool
  98. operator!=(const std::string& lhs, const string& rhs) {return lhs != rhs.str;}
  99. inline bool
  100. operator< (const std::string& lhs, const string& rhs) {return lhs < rhs.str;}
  101. inline bool
  102. operator> (const std::string& lhs, const string& rhs) {return lhs > rhs.str;}
  103. inline bool
  104. operator<=(const std::string& lhs, const string& rhs) {return lhs <= rhs.str;}
  105. inline bool
  106. operator>=(const std::string& lhs, const string& rhs) {return lhs >= rhs.str;}
  107. inline bool
  108. operator==(const string& lhs, const char* rhs) {return lhs.str == std::string(rhs);}
  109. inline bool
  110. operator!=(const string& lhs, const char* rhs) {return lhs.str != std::string(rhs);}
  111. inline bool
  112. operator< (const string& lhs, const char* rhs) {return lhs.str < std::string(rhs);}
  113. inline bool
  114. operator> (const string& lhs, const char* rhs) {return lhs.str > std::string(rhs);}
  115. inline bool
  116. operator<=(const string& lhs, const char* rhs) {return lhs.str <= std::string(rhs);}
  117. inline bool
  118. operator>=(const string& lhs, const char* rhs) {return lhs.str >= std::string(rhs);}
  119. inline bool
  120. operator==(const char* lhs, const string& rhs) {return std::string(lhs) == rhs.str;}
  121. inline bool
  122. operator!=(const char* lhs, const string& rhs) {return std::string(lhs) != rhs.str;}
  123. inline bool
  124. operator< (const char* lhs, const string& rhs) {return std::string(lhs) < rhs.str;}
  125. inline bool
  126. operator> (const char* lhs, const string& rhs) {return std::string(lhs) > rhs.str;}
  127. inline bool
  128. operator<=(const char* lhs, const string& rhs) {return std::string(lhs) <= rhs.str;}
  129. inline bool
  130. operator>=(const char* lhs, const string& rhs) {return std::string(lhs) >= rhs.str;}
  131. template<typename charT, typename traits>
  132. std::basic_ostream<charT, traits>&
  133. operator<<(std::basic_ostream<charT, traits>& os, const string& s)
  134. {
  135. if(s.kind == string_t::basic)
  136. {
  137. if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend())
  138. {
  139. // it contains newline. make it multiline string.
  140. os << "\"\"\"\n";
  141. for(auto i=s.str.cbegin(), e=s.str.cend(); i!=e; ++i)
  142. {
  143. switch(*i)
  144. {
  145. case '\\': {os << "\\\\"; break;}
  146. case '\"': {os << "\\\""; break;}
  147. case '\b': {os << "\\b"; break;}
  148. case '\t': {os << "\\t"; break;}
  149. case '\f': {os << "\\f"; break;}
  150. case '\n': {os << '\n'; break;}
  151. case '\r':
  152. {
  153. // since it is a multiline string,
  154. // CRLF is not needed to be escaped.
  155. if(std::next(i) != e && *std::next(i) == '\n')
  156. {
  157. os << "\r\n";
  158. ++i;
  159. }
  160. else
  161. {
  162. os << "\\r";
  163. }
  164. break;
  165. }
  166. default: {os << *i; break;}
  167. }
  168. }
  169. os << "\\\n\"\"\"";
  170. return os;
  171. }
  172. // no newline. make it inline.
  173. os << "\"";
  174. for(const auto c : s.str)
  175. {
  176. switch(c)
  177. {
  178. case '\\': {os << "\\\\"; break;}
  179. case '\"': {os << "\\\""; break;}
  180. case '\b': {os << "\\b"; break;}
  181. case '\t': {os << "\\t"; break;}
  182. case '\f': {os << "\\f"; break;}
  183. case '\n': {os << "\\n"; break;}
  184. case '\r': {os << "\\r"; break;}
  185. default : {os << c; break;}
  186. }
  187. }
  188. os << "\"";
  189. return os;
  190. }
  191. // the string `s` is literal-string.
  192. if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
  193. std::find(s.str.cbegin(), s.str.cend(), '\'') != s.str.cend() )
  194. {
  195. // contains newline or single quote. make it multiline.
  196. os << "'''\n" << s.str << "'''";
  197. return os;
  198. }
  199. // normal literal string
  200. os << '\'' << s.str << '\'';
  201. return os;
  202. }
  203. } // toml
  204. #endif// TOML11_STRING_H