#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 t_data; typedef rcptr_t t_dataImpl; string() : m_content(rcnew_t<_stringEmpty>()) {} string(const char * p_source) : m_content(rcnew_t(p_source)) {} string(const char * p_source, t_size p_sourceLen) : m_content(rcnew_t(p_source,p_sourceLen)) {} string(char * p_source) : m_content(rcnew_t(p_source)) {} string(char * p_source, t_size p_sourceLen) : m_content(rcnew_t(p_source,p_sourceLen)) {} string(t_data const & p_source) : m_content(p_source) {} string(string_part_ref source) : m_content(rcnew_t(source)) {} template 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 string operator+(const TSource & p_item2) const; template 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 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 static int compare(T1 const& v1, T2 const& v2) { if (is_same_type::value || is_same_type::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 static int compare(T1 const& v1, T2 const& v2) { if (is_same_type::value || is_same_type::value) { return stringCompareCaseInsensitiveEx(stringToRef(v1), stringToRef(v2)); } else { return stringCompareCaseInsensitive(myStringToPtr(v1),myStringToPtr(v2)); } } }; class comparatorCaseInsensitiveASCII : private _comparatorCommon { public: template static int compare(T1 const& v1, T2 const& v2) { if (is_same_type::value || is_same_type::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 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 string::string(const TSource & p_source) { *this = pfc::toString(p_source); } template 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 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 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 : public traits_default {}; }