263 lines
10 KiB
C++
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 {};
|
|
|
|
}
|