// This code is in the public domain -- Ignacio Castaņo #pragma once #ifndef NV_CORE_STRING_H #define NV_CORE_STRING_H #include "Debug.h" #include "Hash.h" // hash //#include // strlen, etc. #if NV_OS_WIN32 #define NV_PATH_SEPARATOR '\\' #else #define NV_PATH_SEPARATOR '/' #endif namespace nv { NVCORE_API uint strHash(const char * str, uint h) NV_PURE; /// String hash based on Bernstein's hash. inline uint strHash(const char * data, uint h = 5381) { uint i = 0; while(data[i] != 0) { h = (33 * h) ^ uint(data[i]); i++; } return h; } template <> struct Hash { uint operator()(const char * str) const { return strHash(str); } }; NVCORE_API uint strLen(const char * str) NV_PURE; // Asserts on NULL strings. NVCORE_API int strDiff(const char * s1, const char * s2) NV_PURE; // Asserts on NULL strings. NVCORE_API int strCaseDiff(const char * s1, const char * s2) NV_PURE; // Asserts on NULL strings. NVCORE_API bool strEqual(const char * s1, const char * s2) NV_PURE; // Accepts NULL strings. NVCORE_API bool strCaseEqual(const char * s1, const char * s2) NV_PURE; // Accepts NULL strings. template <> struct Equal { bool operator()(const char * a, const char * b) const { return strEqual(a, b); } }; NVCORE_API bool strBeginsWith(const char * dst, const char * prefix) NV_PURE; NVCORE_API bool strEndsWith(const char * dst, const char * suffix) NV_PURE; NVCORE_API void strCpy(char * dst, uint size, const char * src); NVCORE_API void strCpy(char * dst, uint size, const char * src, uint len); NVCORE_API void strCat(char * dst, uint size, const char * src); NVCORE_API const char * strSkipWhiteSpace(const char * str); NVCORE_API char * strSkipWhiteSpace(char * str); NVCORE_API bool strMatch(const char * str, const char * pat) NV_PURE; NVCORE_API bool isNumber(const char * str) NV_PURE; /* @@ Implement these two functions and modify StringBuilder to use them? NVCORE_API void strFormat(const char * dst, const char * fmt, ...); NVCORE_API void strFormatList(const char * dst, const char * fmt, va_list arg); template void strFormatSafe(char (&buffer)[count], const char *fmt, ...) __attribute__((format (printf, 2, 3))); template void strFormatSafe(char (&buffer)[count], const char *fmt, ...) { va_list args; va_start(args, fmt); strFormatList(buffer, count, fmt, args); va_end(args); } template void strFormatListSafe(char (&buffer)[count], const char *fmt, va_list arg) { va_list tmp; va_copy(tmp, args); strFormatList(buffer, count, fmt, tmp); va_end(tmp); }*/ template void strCpySafe(char (&buffer)[count], const char *src) { strCpy(buffer, count, src); } template void strCatSafe(char (&buffer)[count], const char * src) { strCat(buffer, count, src); } /// String builder. class NVCORE_CLASS StringBuilder { public: StringBuilder(); explicit StringBuilder( uint size_hint ); StringBuilder(const char * str); StringBuilder(const char * str, uint len); StringBuilder(const StringBuilder & other); ~StringBuilder(); StringBuilder & format( const char * format, ... ) __attribute__((format (printf, 2, 3))); StringBuilder & formatList( const char * format, va_list arg ); StringBuilder & append(const char * str); StringBuilder & append(const char * str, uint len); StringBuilder & appendFormat(const char * format, ...) __attribute__((format (printf, 2, 3))); StringBuilder & appendFormatList(const char * format, va_list arg); StringBuilder & appendSpace(uint n); StringBuilder & number( int i, int base = 10 ); StringBuilder & number( uint i, int base = 10 ); StringBuilder & reserve(uint size_hint); StringBuilder & copy(const char * str); StringBuilder & copy(const char * str, uint len); StringBuilder & copy(const StringBuilder & str); StringBuilder & toLower(); StringBuilder & toUpper(); bool endsWith(const char * str) const; bool beginsWith(const char * str) const; char * reverseFind(char c); void reset(); bool isNull() const { return m_size == 0; } // const char * accessors //operator const char * () const { return m_str; } //operator char * () { return m_str; } const char * str() const { return m_str; } char * str() { return m_str; } char * release(); /// Implement value semantics. StringBuilder & operator=( const StringBuilder & s ) { return copy(s); } /// Implement value semantics. StringBuilder & operator=( const char * s ) { return copy(s); } /// Equal operator. bool operator==( const StringBuilder & s ) const { return strMatch(s.m_str, m_str); } /// Return the exact length. uint length() const { return isNull() ? 0 : strLen(m_str); } /// Return the size of the string container. uint capacity() const { return m_size; } /// Return the hash of the string. uint hash() const { return isNull() ? 0 : strHash(m_str); } // Swap strings. friend void swap(StringBuilder & a, StringBuilder & b); protected: /// Size of the string container. uint m_size; /// String. char * m_str; }; /// Path string. @@ This should be called PathBuilder. class NVCORE_CLASS Path : public StringBuilder { public: Path() : StringBuilder() {} explicit Path(int size_hint) : StringBuilder(size_hint) {} Path(const char * str) : StringBuilder(str) {} Path(const Path & path) : StringBuilder(path) {} const char * fileName() const; const char * extension() const; void translatePath(char pathSeparator = NV_PATH_SEPARATOR); void appendSeparator(char pathSeparator = NV_PATH_SEPARATOR); void stripFileName(); void stripExtension(); // statics NVCORE_API static char separator(); NVCORE_API static const char * fileName(const char *); NVCORE_API static const char * extension(const char *); NVCORE_API static void translatePath(char * path, char pathSeparator = NV_PATH_SEPARATOR); }; /// String class. class NVCORE_CLASS String { public: /// Constructs a null string. @sa isNull() String() { data = NULL; } /// Constructs a shared copy of str. String(const String & str) { data = str.data; if (data != NULL) addRef(); } /// Constructs a shared string from a standard string. String(const char * str) { setString(str); } /// Constructs a shared string from a standard string. String(const char * str, int length) { setString(str, length); } /// Constructs a shared string from a StringBuilder. String(const StringBuilder & str) { setString(str); } /// Dtor. ~String() { release(); } String clone() const; /// Release the current string and allocate a new one. const String & operator=( const char * str ) { release(); setString( str ); return *this; } /// Release the current string and allocate a new one. const String & operator=( const StringBuilder & str ) { release(); setString( str ); return *this; } /// Implement value semantics. String & operator=( const String & str ) { if (str.data != data) { release(); data = str.data; addRef(); } return *this; } /// Equal operator. bool operator==( const String & str ) const { return strMatch(str.data, data); } /// Equal operator. bool operator==( const char * str ) const { return strMatch(str, data); } /// Not equal operator. bool operator!=( const String & str ) const { return !strMatch(str.data, data); } /// Not equal operator. bool operator!=( const char * str ) const { return !strMatch(str, data); } /// Returns true if this string is the null string. bool isNull() const { return data == NULL; } /// Return the exact length. uint length() const { nvDebugCheck(data != NULL); return strLen(data); } /// Return the hash of the string. uint hash() const { nvDebugCheck(data != NULL); return strHash(data); } /// const char * cast operator. operator const char * () const { return data; } /// Get string pointer. const char * str() const { return data; } private: // Add reference count. void addRef(); // Decrease reference count. void release(); uint16 getRefCount() const { nvDebugCheck(data != NULL); return *reinterpret_cast(data - 2); } void setRefCount(uint16 count) { nvDebugCheck(data != NULL); nvCheck(count < 0xFFFF); *reinterpret_cast(const_cast(data - 2)) = uint16(count); } void setData(const char * str) { data = str + 2; } void allocString(const char * str) { allocString(str, strLen(str)); } void allocString(const char * str, uint length); void setString(const char * str); void setString(const char * str, uint length); void setString(const StringBuilder & str); // Swap strings. friend void swap(String & a, String & b); private: const char * data; }; template <> struct Hash { uint operator()(const String & str) const { return str.hash(); } }; // Like AutoPtr, but for const char strings. class AutoString { NV_FORBID_COPY(AutoString); NV_FORBID_HEAPALLOC(); public: // Ctor. AutoString(const char * p = NULL) : m_ptr(p) { } #if NV_CC_CPP11 // Move ctor. AutoString(AutoString && ap) : m_ptr(ap.m_ptr) { ap.m_ptr = NULL; } #endif // Dtor. Deletes owned pointer. ~AutoString() { delete [] m_ptr; m_ptr = NULL; } // Delete owned pointer and assign new one. void operator=(const char * p) { if (p != m_ptr) { delete [] m_ptr; m_ptr = p; } } // Get pointer. const char * ptr() const { return m_ptr; } operator const char *() const { return m_ptr; } // Relinquish ownership of the underlying pointer and returns that pointer. const char * release() { const char * tmp = m_ptr; m_ptr = NULL; return tmp; } // comparison operators. friend bool operator == (const AutoString & ap, const char * const p) { return (ap.ptr() == p); } friend bool operator != (const AutoString & ap, const char * const p) { return (ap.ptr() != p); } friend bool operator == (const char * const p, const AutoString & ap) { return (ap.ptr() == p); } friend bool operator != (const char * const p, const AutoString & ap) { return (ap.ptr() != p); } private: const char * m_ptr; }; } // nv namespace #endif // NV_CORE_STRING_H