Files
foobar2000-sdk/pfc/stringNew.h
2021-12-14 00:28:25 -07:00

263 lines
10 KiB
C++

#pragma once
namespace pfc {
//helper, const methods only
class _stringEmpty : public string_base {
public:
const char * get_ptr() const {return "";}
void add_string(const char * ,t_size) {throw exception_not_implemented();}
void set_string(const char * ,t_size) {throw exception_not_implemented();}
void truncate(t_size) {throw exception_not_implemented();}
t_size get_length() const {return 0;}
char * lock_buffer(t_size) {throw exception_not_implemented();}
void unlock_buffer() {throw exception_not_implemented();}
};
class stringp;
//! New EXPERIMENTAL string class, allowing efficient copies and returning from functions. \n
//! Does not implement the string_base interface so you still need string8 in many cases. \n
//! Safe to pass between DLLs, but since a reference is used, objects possibly created by other DLLs must be released before owning DLLs are unloaded.
class string {
public:
typedef rcptr_t<string_base const> t_data;
typedef rcptr_t<string8> t_dataImpl;
string() : m_content(rcnew_t<_stringEmpty>()) {}
string(const char * p_source) : m_content(rcnew_t<string8>(p_source)) {}
string(const char * p_source, t_size p_sourceLen) : m_content(rcnew_t<string8>(p_source,p_sourceLen)) {}
string(char * p_source) : m_content(rcnew_t<string8>(p_source)) {}
string(char * p_source, t_size p_sourceLen) : m_content(rcnew_t<string8>(p_source,p_sourceLen)) {}
string(t_data const & p_source) : m_content(p_source) {}
string(string_part_ref source) : m_content(rcnew_t<string8>(source)) {}
template<typename TSource> string(const TSource & p_source);
string(const string& other) : m_content(other.m_content) {}
string(string&& other) : m_content(std::move(other.m_content)) {}
const string& operator=(const string& other) {m_content = other.m_content; return *this;}
const string& operator=(string&& other) {m_content = std::move(other.m_content); return *this;}
string const & toString() const {return *this;}
//warning, not length-checked anymore!
static string g_concatenateRaw(const char * item1, t_size len1, const char * item2, t_size len2) {
t_dataImpl impl; impl.new_t();
char * buffer = impl->lock_buffer(len1+len2);
memcpy_t(buffer,item1,len1);
memcpy_t(buffer+len1,item2,len2);
impl->unlock_buffer();
return string(t_data(impl));
}
string operator+(const string& p_item2) const {
return g_concatenateRaw(ptr(),length(),p_item2.ptr(),p_item2.length());
}
string operator+(const char * p_item2) const {
return g_concatenateRaw(ptr(),length(),p_item2,strlen(p_item2));
}
template<typename TSource> string operator+(const TSource & p_item2) const;
template<typename TSource>
const string & operator+=(const TSource & p_item) {
*this = *this + p_item;
return *this;
}
string subString(t_size base) const {
if (base > length()) throw exception_overflow();
return string(ptr() + base);
}
string subString(t_size base, t_size count) const {
return string(ptr() + base,count);
}
string toLower() const {
string8_fastalloc temp; temp.prealloc(128);
stringToLowerAppend(temp,ptr(),SIZE_MAX);
return string(temp.get_ptr());
}
string toUpper() const {
string8_fastalloc temp; temp.prealloc(128);
stringToUpperAppend(temp,ptr(),SIZE_MAX);
return string(temp.get_ptr());
}
string clone() const {return string(ptr());}
//! @returns ~0 if not found.
t_size indexOf(char c,t_size base = 0) const;
//! @returns ~0 if not found.
t_size lastIndexOf(char c,t_size base = SIZE_MAX) const;
//! @returns ~0 if not found.
t_size indexOf(stringp s,t_size base = 0) const;
//! @returns ~0 if not found.
t_size lastIndexOf(stringp s,t_size base = SIZE_MAX) const;
//! @returns ~0 if not found.
t_size indexOfAnyChar(stringp s,t_size base = 0) const;
//! @returns ~0 if not found.
t_size lastIndexOfAnyChar(stringp s,t_size base = SIZE_MAX) const;
bool contains(char c) const;
bool contains(stringp s) const;
bool containsAnyChar(stringp s) const;
bool startsWith(char c) const;
bool startsWith(string s) const;
bool endsWith(char c) const;
bool endsWith(string s) const;
char firstChar() const;
char lastChar() const;
string replace(stringp strOld, stringp strNew) const;
static int g_compare(const string & p_item1, const string & p_item2) {return strcmp(p_item1.ptr(),p_item2.ptr());}
bool operator==(const string& p_other) const {return g_compare(*this,p_other) == 0;}
bool operator!=(const string& p_other) const {return g_compare(*this,p_other) != 0;}
bool operator<(const string& p_other) const {return g_compare(*this,p_other) < 0;}
bool operator>(const string& p_other) const {return g_compare(*this,p_other) > 0;}
bool operator<=(const string& p_other) const {return g_compare(*this,p_other) <= 0;}
bool operator>=(const string& p_other) const {return g_compare(*this,p_other) >= 0;}
const char * ptr() const {return m_content->get_ptr();}
const char * get_ptr() const {return m_content->get_ptr();}
const char * c_str() const { return get_ptr(); }
t_size length() const {return m_content->get_length();}
t_size get_length() const {return m_content->get_length();}
void set_string(const char * ptr, t_size len = SIZE_MAX) {
*this = string(ptr, len);
}
static bool isNonTextChar(char c) {return c >= 0 && c < 32;}
char operator[](t_size p_index) const {
PFC_ASSERT(p_index <= length());
return ptr()[p_index];
}
bool isEmpty() const {return length() == 0;}
class _comparatorCommon {
protected:
template<typename T> static const char * myStringToPtr(const T& val) {return stringToPtr(val);}
static const char * myStringToPtr(string_part_ref) {
PFC_ASSERT(!"Should never get here"); throw exception_invalid_params();
}
};
class comparatorCaseSensitive : private _comparatorCommon {
public:
template<typename T1,typename T2>
static int compare(T1 const& v1, T2 const& v2) {
if (is_same_type<T1, string_part_ref>::value || is_same_type<T2, string_part_ref>::value) {
return compare_ex(stringToRef(v1), stringToRef(v2));
} else {
return strcmp(myStringToPtr(v1),myStringToPtr(v2));
}
}
static int compare_ex(string_part_ref v1, string_part_ref v2) {
return strcmp_ex(v1.m_ptr, v1.m_len, v2.m_ptr, v2.m_len);
}
static int compare_ex(const char * v1, t_size l1, const char * v2, t_size l2) {
return strcmp_ex(v1, l1, v2, l2);
}
};
class comparatorCaseInsensitive : private _comparatorCommon {
public:
template<typename T1,typename T2>
static int compare(T1 const& v1, T2 const& v2) {
if (is_same_type<T1, string_part_ref>::value || is_same_type<T2, string_part_ref>::value) {
return stringCompareCaseInsensitiveEx(stringToRef(v1), stringToRef(v2));
} else {
return stringCompareCaseInsensitive(myStringToPtr(v1),myStringToPtr(v2));
}
}
};
class comparatorCaseInsensitiveASCII : private _comparatorCommon {
public:
template<typename T1,typename T2>
static int compare(T1 const& v1, T2 const& v2) {
if (is_same_type<T1, string_part_ref>::value || is_same_type<T2, string_part_ref>::value) {
return compare_ex(stringToRef(v1), stringToRef(v2));
} else {
return stricmp_ascii(myStringToPtr(v1),myStringToPtr(v2));
}
}
static int compare_ex(string_part_ref v1, string_part_ref v2) {
return stricmp_ascii_ex(v1.m_ptr, v1.m_len, v2.m_ptr, v2.m_len);
}
static int compare_ex(const char * v1, t_size l1, const char * v2, t_size l2) {
return stricmp_ascii_ex(v1, l1, v2, l2);
}
};
static bool g_equals(const string & p_item1, const string & p_item2) {return p_item1 == p_item2;}
static bool g_equalsCaseInsensitive(const string & p_item1, const string & p_item2) {return comparatorCaseInsensitive::compare(p_item1,p_item2) == 0;}
t_data _content() const {return m_content;}
private:
t_data m_content;
};
template<typename T> inline string toString(T const& val) {return val.toString();}
template<> inline string toString(t_int64 const& val) {return format_int(val).get_ptr();}
template<> inline string toString(t_int32 const& val) {return format_int(val).get_ptr();}
template<> inline string toString(t_int16 const& val) {return format_int(val).get_ptr();}
template<> inline string toString(t_uint64 const& val) {return format_uint(val).get_ptr();}
template<> inline string toString(t_uint32 const& val) {return format_uint(val).get_ptr();}
template<> inline string toString(t_uint16 const& val) {return format_uint(val).get_ptr();}
template<> inline string toString(float const& val) {return format_float(val).get_ptr();}
template<> inline string toString(double const& val) {return format_float(val).get_ptr();}
template<> inline string toString(char const& val) {return string(&val,1);}
inline const char * toString(std::exception const& val) {return val.what();}
template<typename TSource> string::string(const TSource & p_source) {
*this = pfc::toString(p_source);
}
template<typename TSource> string string::operator+(const TSource & p_item2) const {
return *this + pfc::toString(p_item2);
}
//! "String parameter" helper class, to use in function parameters, allowing functions to take any type of string as a parameter (const char*, string_base, string).
class stringp {
public:
stringp(const char * ptr) : m_ptr(ptr) {}
stringp(string const &s) : m_ptr(s.ptr()), m_s(s._content()) {}
stringp(string_base const &s) : m_ptr(s.get_ptr()) {}
template<typename TWhat> stringp(const TWhat& in) : m_ptr(in.toString()) {}
operator const char*() const {return m_ptr;}
const char * ptr() const {return m_ptr;}
const char * get_ptr() const {return m_ptr;}
string str() const {return m_s.is_valid() ? string(m_s) : string(m_ptr);}
operator string() const {return str();}
string toString() const {return str();}
t_size length() const {return m_s.is_valid() ? m_s->length() : strlen(m_ptr);}
const char * c_str() const { return ptr(); }
private:
const char * const m_ptr;
string::t_data m_s;
};
template<typename TList>
string stringCombineList(const TList & list, stringp separator) {
typename TList::const_iterator iter = list.first();
string acc;
if (iter.is_valid()) {
acc = *iter;
for(++iter; iter.is_valid(); ++iter) {
acc = acc + separator + *iter;
}
}
return acc;
}
class string;
template<> class traits_t<string> : public traits_default {};
}