forked from lix-project/lix
226 lines
7.6 KiB
C++
226 lines
7.6 KiB
C++
// Copyright Toru Niina 2017.
|
|
// Distributed under the MIT License.
|
|
#ifndef TOML11_STRING_HPP
|
|
#define TOML11_STRING_HPP
|
|
#include <cstdint>
|
|
|
|
#include <algorithm>
|
|
#include <string>
|
|
|
|
#if __cplusplus >= 201703L
|
|
#if __has_include(<string_view>)
|
|
#define TOML11_USING_STRING_VIEW 1
|
|
#include <string_view>
|
|
#endif
|
|
#endif
|
|
|
|
namespace toml
|
|
{
|
|
|
|
enum class string_t : std::uint8_t
|
|
{
|
|
basic = 0,
|
|
literal = 1,
|
|
};
|
|
|
|
struct string
|
|
{
|
|
string() = default;
|
|
~string() = default;
|
|
string(const string& s) = default;
|
|
string(string&& s) = default;
|
|
string& operator=(const string& s) = default;
|
|
string& operator=(string&& s) = default;
|
|
|
|
string(const std::string& s): kind(string_t::basic), str(s){}
|
|
string(const std::string& s, string_t k): kind(k), str(s){}
|
|
string(const char* s): kind(string_t::basic), str(s){}
|
|
string(const char* s, string_t k): kind(k), str(s){}
|
|
|
|
string(std::string&& s): kind(string_t::basic), str(std::move(s)){}
|
|
string(std::string&& s, string_t k): kind(k), str(std::move(s)){}
|
|
|
|
string& operator=(const std::string& s)
|
|
{kind = string_t::basic; str = s; return *this;}
|
|
string& operator=(std::string&& s)
|
|
{kind = string_t::basic; str = std::move(s); return *this;}
|
|
|
|
operator std::string& () & noexcept {return str;}
|
|
operator std::string const& () const& noexcept {return str;}
|
|
operator std::string&& () && noexcept {return std::move(str);}
|
|
|
|
string& operator+=(const char* rhs) {str += rhs; return *this;}
|
|
string& operator+=(const char rhs) {str += rhs; return *this;}
|
|
string& operator+=(const std::string& rhs) {str += rhs; return *this;}
|
|
string& operator+=(const string& rhs) {str += rhs.str; return *this;}
|
|
|
|
#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
|
|
explicit string(std::string_view s): kind(string_t::basic), str(s){}
|
|
string(std::string_view s, string_t k): kind(k), str(s){}
|
|
|
|
string& operator=(std::string_view s)
|
|
{kind = string_t::basic; str = s; return *this;}
|
|
|
|
explicit operator std::string_view() const noexcept
|
|
{return std::string_view(str);}
|
|
|
|
string& operator+=(const std::string_view& rhs) {str += rhs; return *this;}
|
|
#endif
|
|
|
|
string_t kind;
|
|
std::string str;
|
|
};
|
|
|
|
inline bool operator==(const string& lhs, const string& rhs)
|
|
{
|
|
return lhs.kind == rhs.kind && lhs.str == rhs.str;
|
|
}
|
|
inline bool operator!=(const string& lhs, const string& rhs)
|
|
{
|
|
return !(lhs == rhs);
|
|
}
|
|
inline bool operator<(const string& lhs, const string& rhs)
|
|
{
|
|
return (lhs.kind == rhs.kind) ? (lhs.str < rhs.str) : (lhs.kind < rhs.kind);
|
|
}
|
|
inline bool operator>(const string& lhs, const string& rhs)
|
|
{
|
|
return rhs < lhs;
|
|
}
|
|
inline bool operator<=(const string& lhs, const string& rhs)
|
|
{
|
|
return !(rhs < lhs);
|
|
}
|
|
inline bool operator>=(const string& lhs, const string& rhs)
|
|
{
|
|
return !(lhs < rhs);
|
|
}
|
|
|
|
inline bool
|
|
operator==(const string& lhs, const std::string& rhs) {return lhs.str == rhs;}
|
|
inline bool
|
|
operator!=(const string& lhs, const std::string& rhs) {return lhs.str != rhs;}
|
|
inline bool
|
|
operator< (const string& lhs, const std::string& rhs) {return lhs.str < rhs;}
|
|
inline bool
|
|
operator> (const string& lhs, const std::string& rhs) {return lhs.str > rhs;}
|
|
inline bool
|
|
operator<=(const string& lhs, const std::string& rhs) {return lhs.str <= rhs;}
|
|
inline bool
|
|
operator>=(const string& lhs, const std::string& rhs) {return lhs.str >= rhs;}
|
|
|
|
inline bool
|
|
operator==(const std::string& lhs, const string& rhs) {return lhs == rhs.str;}
|
|
inline bool
|
|
operator!=(const std::string& lhs, const string& rhs) {return lhs != rhs.str;}
|
|
inline bool
|
|
operator< (const std::string& lhs, const string& rhs) {return lhs < rhs.str;}
|
|
inline bool
|
|
operator> (const std::string& lhs, const string& rhs) {return lhs > rhs.str;}
|
|
inline bool
|
|
operator<=(const std::string& lhs, const string& rhs) {return lhs <= rhs.str;}
|
|
inline bool
|
|
operator>=(const std::string& lhs, const string& rhs) {return lhs >= rhs.str;}
|
|
|
|
inline bool
|
|
operator==(const string& lhs, const char* rhs) {return lhs.str == std::string(rhs);}
|
|
inline bool
|
|
operator!=(const string& lhs, const char* rhs) {return lhs.str != std::string(rhs);}
|
|
inline bool
|
|
operator< (const string& lhs, const char* rhs) {return lhs.str < std::string(rhs);}
|
|
inline bool
|
|
operator> (const string& lhs, const char* rhs) {return lhs.str > std::string(rhs);}
|
|
inline bool
|
|
operator<=(const string& lhs, const char* rhs) {return lhs.str <= std::string(rhs);}
|
|
inline bool
|
|
operator>=(const string& lhs, const char* rhs) {return lhs.str >= std::string(rhs);}
|
|
|
|
inline bool
|
|
operator==(const char* lhs, const string& rhs) {return std::string(lhs) == rhs.str;}
|
|
inline bool
|
|
operator!=(const char* lhs, const string& rhs) {return std::string(lhs) != rhs.str;}
|
|
inline bool
|
|
operator< (const char* lhs, const string& rhs) {return std::string(lhs) < rhs.str;}
|
|
inline bool
|
|
operator> (const char* lhs, const string& rhs) {return std::string(lhs) > rhs.str;}
|
|
inline bool
|
|
operator<=(const char* lhs, const string& rhs) {return std::string(lhs) <= rhs.str;}
|
|
inline bool
|
|
operator>=(const char* lhs, const string& rhs) {return std::string(lhs) >= rhs.str;}
|
|
|
|
template<typename charT, typename traits>
|
|
std::basic_ostream<charT, traits>&
|
|
operator<<(std::basic_ostream<charT, traits>& os, const string& s)
|
|
{
|
|
if(s.kind == string_t::basic)
|
|
{
|
|
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend())
|
|
{
|
|
// it contains newline. make it multiline string.
|
|
os << "\"\"\"\n";
|
|
for(auto i=s.str.cbegin(), e=s.str.cend(); i!=e; ++i)
|
|
{
|
|
switch(*i)
|
|
{
|
|
case '\\': {os << "\\\\"; break;}
|
|
case '\"': {os << "\\\""; break;}
|
|
case '\b': {os << "\\b"; break;}
|
|
case '\t': {os << "\\t"; break;}
|
|
case '\f': {os << "\\f"; break;}
|
|
case '\n': {os << '\n'; break;}
|
|
case '\r':
|
|
{
|
|
// since it is a multiline string,
|
|
// CRLF is not needed to be escaped.
|
|
if(std::next(i) != e && *std::next(i) == '\n')
|
|
{
|
|
os << "\r\n";
|
|
++i;
|
|
}
|
|
else
|
|
{
|
|
os << "\\r";
|
|
}
|
|
break;
|
|
}
|
|
default: {os << *i; break;}
|
|
}
|
|
}
|
|
os << "\\\n\"\"\"";
|
|
return os;
|
|
}
|
|
// no newline. make it inline.
|
|
os << "\"";
|
|
for(const auto c : s.str)
|
|
{
|
|
switch(c)
|
|
{
|
|
case '\\': {os << "\\\\"; break;}
|
|
case '\"': {os << "\\\""; break;}
|
|
case '\b': {os << "\\b"; break;}
|
|
case '\t': {os << "\\t"; break;}
|
|
case '\f': {os << "\\f"; break;}
|
|
case '\n': {os << "\\n"; break;}
|
|
case '\r': {os << "\\r"; break;}
|
|
default : {os << c; break;}
|
|
}
|
|
}
|
|
os << "\"";
|
|
return os;
|
|
}
|
|
// the string `s` is literal-string.
|
|
if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
|
|
std::find(s.str.cbegin(), s.str.cend(), '\'') != s.str.cend() )
|
|
{
|
|
// contains newline or single quote. make it multiline.
|
|
os << "'''\n" << s.str << "'''";
|
|
return os;
|
|
}
|
|
// normal literal string
|
|
os << '\'' << s.str << '\'';
|
|
return os;
|
|
}
|
|
|
|
} // toml
|
|
#endif// TOML11_STRING_H
|