- moved most basic utility code without any dependencies on the rest of the engine to 'common' directory.
Again the objective is easier sharing with Raze.
This commit is contained in:
parent
ace3e29473
commit
fb1a7679ec
28 changed files with 293 additions and 227 deletions
479
src/common/utility/zstring.h
Normal file
479
src/common/utility/zstring.h
Normal file
|
|
@ -0,0 +1,479 @@
|
|||
#pragma once
|
||||
/*
|
||||
** zstring.h
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2005-2007 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <string>
|
||||
#include "tarray.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define PRINTFISH(x) __attribute__((format(printf, 2, x)))
|
||||
#else
|
||||
#define PRINTFISH(x)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define IGNORE_FORMAT_PRE \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wformat\"") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wformat-extra-args\"")
|
||||
#define IGNORE_FORMAT_POST _Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
#define IGNORE_FORMAT_PRE
|
||||
#define IGNORE_FORMAT_POST
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
std::wstring WideString(const char *);
|
||||
#endif
|
||||
|
||||
struct FStringData
|
||||
{
|
||||
unsigned int Len; // Length of string, excluding terminating null
|
||||
unsigned int AllocLen; // Amount of memory allocated for string
|
||||
int RefCount; // < 0 means it's locked
|
||||
// char StrData[xxx];
|
||||
|
||||
char *Chars()
|
||||
{
|
||||
return (char *)(this + 1);
|
||||
}
|
||||
|
||||
const char *Chars() const
|
||||
{
|
||||
return (const char *)(this + 1);
|
||||
}
|
||||
|
||||
char *AddRef()
|
||||
{
|
||||
if (RefCount < 0)
|
||||
{
|
||||
return (char *)(MakeCopy() + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
RefCount++;
|
||||
return (char *)(this + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Release()
|
||||
{
|
||||
assert (RefCount != 0);
|
||||
|
||||
if (--RefCount <= 0)
|
||||
{
|
||||
Dealloc();
|
||||
}
|
||||
}
|
||||
|
||||
FStringData *MakeCopy();
|
||||
|
||||
static FStringData *Alloc (size_t strlen);
|
||||
FStringData *Realloc (size_t newstrlen);
|
||||
void Dealloc ();
|
||||
};
|
||||
|
||||
struct FNullStringData
|
||||
{
|
||||
unsigned int Len;
|
||||
unsigned int AllocLen;
|
||||
int RefCount;
|
||||
char Nothing[2];
|
||||
};
|
||||
|
||||
enum ELumpNum
|
||||
{
|
||||
};
|
||||
|
||||
class FString
|
||||
{
|
||||
public:
|
||||
FString () { ResetToNull(); }
|
||||
|
||||
// Copy constructors
|
||||
FString (const FString &other) { AttachToOther (other); }
|
||||
FString (FString &&other) : Chars(other.Chars) { other.ResetToNull(); }
|
||||
FString (const char *copyStr);
|
||||
FString (const char *copyStr, size_t copyLen);
|
||||
FString (char oneChar);
|
||||
FString(const TArray<char> & source) : FString(source.Data(), source.Size()) {}
|
||||
FString(const TArray<uint8_t> & source) : FString((char*)source.Data(), source.Size()) {}
|
||||
// This is intentionally #ifdef'd. The only code which needs this is parts of the Windows backend that receive Unicode text from the system.
|
||||
#ifdef _WIN32
|
||||
explicit FString(const wchar_t *copyStr);
|
||||
FString &operator = (const wchar_t *copyStr);
|
||||
std::wstring WideString() const { return ::WideString(Chars); }
|
||||
#endif
|
||||
|
||||
// Concatenation constructors
|
||||
FString (const FString &head, const FString &tail);
|
||||
FString (const FString &head, const char *tail);
|
||||
FString (const FString &head, char tail);
|
||||
FString (const char *head, const FString &tail);
|
||||
FString (const char *head, const char *tail);
|
||||
FString (char head, const FString &tail);
|
||||
|
||||
// Other constructors
|
||||
FString (ELumpNum); // Create from a lump
|
||||
|
||||
~FString ();
|
||||
|
||||
// Discard string's contents, create a new buffer, and lock it.
|
||||
char *LockNewBuffer(size_t len);
|
||||
|
||||
char *LockBuffer(); // Obtain write access to the character buffer
|
||||
void UnlockBuffer(); // Allow shared access to the character buffer
|
||||
|
||||
void Swap(FString &other)
|
||||
{
|
||||
std::swap(Chars, other.Chars);
|
||||
}
|
||||
|
||||
operator const char *() const { return Chars; }
|
||||
|
||||
const char *GetChars() const { return Chars; }
|
||||
|
||||
const char &operator[] (int index) const { return Chars[index]; }
|
||||
#if defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER)
|
||||
// Compiling 32-bit Windows source with MSVC: size_t is typedefed to an
|
||||
// unsigned int with the 64-bit portability warning attribute, so the
|
||||
// prototype cannot substitute unsigned int for size_t, or you get
|
||||
// spurious warnings.
|
||||
const char &operator[] (size_t index) const { return Chars[index]; }
|
||||
#else
|
||||
const char &operator[] (unsigned int index) const { return Chars[index]; }
|
||||
#endif
|
||||
const char &operator[] (unsigned long index) const { return Chars[index]; }
|
||||
const char &operator[] (unsigned long long index) const { return Chars[index]; }
|
||||
|
||||
FString &operator = (const FString &other);
|
||||
FString &operator = (FString &&other);
|
||||
FString &operator = (const char *copyStr);
|
||||
|
||||
FString operator + (const FString &tail) const;
|
||||
FString operator + (const char *tail) const;
|
||||
FString operator + (char tail) const;
|
||||
friend FString operator + (const char *head, const FString &tail);
|
||||
friend FString operator + (char head, const FString &tail);
|
||||
|
||||
FString &operator += (const FString &tail);
|
||||
FString &operator += (const char *tail);
|
||||
FString &operator += (char tail);
|
||||
FString &AppendCStrPart (const char *tail, size_t tailLen);
|
||||
FString &CopyCStrPart(const char *tail, size_t tailLen);
|
||||
|
||||
FString &operator << (const FString &tail) { return *this += tail; }
|
||||
FString &operator << (const char *tail) { return *this += tail; }
|
||||
FString &operator << (char tail) { return *this += tail; }
|
||||
|
||||
const char &Front() const { assert(IsNotEmpty()); return Chars[0]; }
|
||||
const char &Back() const { assert(IsNotEmpty()); return Chars[Len() - 1]; }
|
||||
|
||||
FString Left (size_t numChars) const;
|
||||
FString Right (size_t numChars) const;
|
||||
FString Mid (size_t pos, size_t numChars = ~(size_t)0) const;
|
||||
|
||||
void AppendCharacter(int codepoint);
|
||||
void DeleteLastCharacter();
|
||||
|
||||
long IndexOf (const FString &substr, long startIndex=0) const;
|
||||
long IndexOf (const char *substr, long startIndex=0) const;
|
||||
long IndexOf (char subchar, long startIndex=0) const;
|
||||
|
||||
long IndexOfAny (const FString &charset, long startIndex=0) const;
|
||||
long IndexOfAny (const char *charset, long startIndex=0) const;
|
||||
|
||||
// This is only kept for backwards compatibility with old ZScript versions that used this function and depend on its bug.
|
||||
long LastIndexOf (char subchar) const;
|
||||
long LastIndexOfBroken (const FString &substr, long endIndex) const;
|
||||
long LastIndexOf (char subchar, long endIndex) const;
|
||||
|
||||
long LastIndexOfAny (const FString &charset) const;
|
||||
long LastIndexOfAny (const char *charset) const;
|
||||
long LastIndexOfAny (const FString &charset, long endIndex) const;
|
||||
long LastIndexOfAny (const char *charset, long endIndex) const;
|
||||
|
||||
long LastIndexOf (const FString &substr) const;
|
||||
long LastIndexOf (const FString &substr, long endIndex) const;
|
||||
long LastIndexOf (const char *substr) const;
|
||||
long LastIndexOf (const char *substr, long endIndex) const;
|
||||
long LastIndexOf (const char *substr, long endIndex, size_t substrlen) const;
|
||||
|
||||
void ToUpper ();
|
||||
void ToLower ();
|
||||
FString MakeUpper() const;
|
||||
FString MakeLower() const;
|
||||
|
||||
void StripLeft ();
|
||||
void StripLeft (const FString &charset);
|
||||
void StripLeft (const char *charset);
|
||||
|
||||
void StripRight ();
|
||||
void StripRight (const FString &charset);
|
||||
void StripRight (const char *charset);
|
||||
|
||||
void StripLeftRight ();
|
||||
void StripLeftRight (const FString &charset);
|
||||
void StripLeftRight (const char *charset);
|
||||
|
||||
void Insert (size_t index, const FString &instr);
|
||||
void Insert (size_t index, const char *instr);
|
||||
void Insert (size_t index, const char *instr, size_t instrlen);
|
||||
|
||||
template<typename Func>
|
||||
void ReplaceChars (Func IsOldChar, char newchar)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
LockBuffer();
|
||||
for (i = 0, j = Len(); i < j; ++i)
|
||||
{
|
||||
if (IsOldChar(Chars[i]))
|
||||
{
|
||||
Chars[i] = newchar;
|
||||
}
|
||||
}
|
||||
UnlockBuffer();
|
||||
}
|
||||
|
||||
void ReplaceChars (char oldchar, char newchar);
|
||||
void ReplaceChars (const char *oldcharset, char newchar);
|
||||
|
||||
template<typename Func>
|
||||
void StripChars (Func IsKillChar)
|
||||
{
|
||||
size_t read, write, mylen;
|
||||
|
||||
LockBuffer();
|
||||
for (read = write = 0, mylen = Len(); read < mylen; ++read)
|
||||
{
|
||||
if (!IsKillChar(Chars[read]))
|
||||
{
|
||||
Chars[write++] = Chars[read];
|
||||
}
|
||||
}
|
||||
Chars[write] = '\0';
|
||||
ReallocBuffer (write);
|
||||
UnlockBuffer();
|
||||
}
|
||||
|
||||
void StripChars (char killchar);
|
||||
void StripChars (const char *killcharset);
|
||||
|
||||
void MergeChars (char merger);
|
||||
void MergeChars (char merger, char newchar);
|
||||
void MergeChars (const char *charset, char newchar);
|
||||
|
||||
void Substitute (const FString &oldstr, const FString &newstr);
|
||||
void Substitute (const char *oldstr, const FString &newstr);
|
||||
void Substitute (const FString &oldstr, const char *newstr);
|
||||
void Substitute (const char *oldstr, const char *newstr);
|
||||
void Substitute (const char *oldstr, const char *newstr, size_t oldstrlen, size_t newstrlen);
|
||||
|
||||
void Format (const char *fmt, ...) PRINTFISH(3);
|
||||
void AppendFormat (const char *fmt, ...) PRINTFISH(3);
|
||||
void VFormat (const char *fmt, va_list arglist) PRINTFISH(0);
|
||||
void VAppendFormat (const char *fmt, va_list arglist) PRINTFISH(0);
|
||||
|
||||
bool IsInt () const;
|
||||
bool IsFloat () const;
|
||||
int64_t ToLong (int base=0) const;
|
||||
uint64_t ToULong (int base=0) const;
|
||||
double ToDouble () const;
|
||||
|
||||
size_t Len() const { return Data()->Len; }
|
||||
size_t CharacterCount() const;
|
||||
int GetNextCharacter(int &position) const;
|
||||
bool IsEmpty() const { return Len() == 0; }
|
||||
bool IsNotEmpty() const { return Len() != 0; }
|
||||
|
||||
void Truncate (size_t newlen);
|
||||
void Remove(size_t index, size_t remlen);
|
||||
|
||||
int Compare (const FString &other) const { return strcmp (Chars, other.Chars); }
|
||||
int Compare (const char *other) const { return strcmp (Chars, other); }
|
||||
int Compare(const FString &other, int len) const { return strncmp(Chars, other.Chars, len); }
|
||||
int Compare(const char *other, int len) const { return strncmp(Chars, other, len); }
|
||||
|
||||
int CompareNoCase (const FString &other) const { return stricmp (Chars, other.Chars); }
|
||||
int CompareNoCase (const char *other) const { return stricmp (Chars, other); }
|
||||
int CompareNoCase(const FString &other, int len) const { return strnicmp(Chars, other.Chars, len); }
|
||||
int CompareNoCase(const char *other, int len) const { return strnicmp(Chars, other, len); }
|
||||
|
||||
enum EmptyTokenType
|
||||
{
|
||||
TOK_SKIPEMPTY = 0,
|
||||
TOK_KEEPEMPTY = 1,
|
||||
};
|
||||
|
||||
TArray<FString> Split(const FString &delimiter, EmptyTokenType keepEmpty = TOK_KEEPEMPTY) const;
|
||||
TArray<FString> Split(const char *delimiter, EmptyTokenType keepEmpty = TOK_KEEPEMPTY) const;
|
||||
void Split(TArray<FString>& tokens, const FString &delimiter, EmptyTokenType keepEmpty = TOK_KEEPEMPTY) const;
|
||||
void Split(TArray<FString>& tokens, const char *delimiter, EmptyTokenType keepEmpty = TOK_KEEPEMPTY) const;
|
||||
|
||||
protected:
|
||||
const FStringData *Data() const { return (FStringData *)Chars - 1; }
|
||||
FStringData *Data() { return (FStringData *)Chars - 1; }
|
||||
|
||||
void ResetToNull()
|
||||
{
|
||||
NullString.RefCount++;
|
||||
Chars = &NullString.Nothing[0];
|
||||
}
|
||||
|
||||
void AttachToOther (const FString &other);
|
||||
void AllocBuffer (size_t len);
|
||||
void ReallocBuffer (size_t newlen);
|
||||
|
||||
static int FormatHelper (void *data, const char *str, int len);
|
||||
static void StrCopy (char *to, const char *from, size_t len);
|
||||
static void StrCopy (char *to, const FString &from);
|
||||
|
||||
char *Chars;
|
||||
|
||||
static FNullStringData NullString;
|
||||
|
||||
friend struct FStringData;
|
||||
|
||||
public:
|
||||
bool operator == (const FString &other) const
|
||||
{
|
||||
return Compare(other) == 0;
|
||||
}
|
||||
|
||||
bool operator != (const FString &other) const
|
||||
{
|
||||
return Compare(other) != 0;
|
||||
}
|
||||
|
||||
bool operator < (const FString &other) const
|
||||
{
|
||||
return Compare(other) < 0;
|
||||
}
|
||||
|
||||
bool operator > (const FString &other) const
|
||||
{
|
||||
return Compare(other) > 0;
|
||||
}
|
||||
|
||||
bool operator <= (const FString &other) const
|
||||
{
|
||||
return Compare(other) <= 0;
|
||||
}
|
||||
|
||||
bool operator >= (const FString &other) const
|
||||
{
|
||||
return Compare(other) >= 0;
|
||||
}
|
||||
|
||||
// These are needed to block the default char * conversion operator from making a mess.
|
||||
bool operator == (const char *) const = delete;
|
||||
bool operator != (const char *) const = delete;
|
||||
bool operator < (const char *) const = delete;
|
||||
bool operator > (const char *) const = delete;
|
||||
bool operator <= (const char *) const = delete;
|
||||
bool operator >= (const char *) const = delete;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
// These are also needed to block the default char * conversion operator from making a mess.
|
||||
bool operator == (const char *, const FString &) = delete;
|
||||
bool operator != (const char *, const FString &) = delete;
|
||||
bool operator < (const char *, const FString &) = delete;
|
||||
bool operator > (const char *, const FString &) = delete;
|
||||
bool operator <= (const char *, const FString &) = delete;
|
||||
bool operator >= (const char *, const FString &) = delete;
|
||||
|
||||
class FStringf : public FString
|
||||
{
|
||||
public:
|
||||
FStringf(const char *fmt, ...);
|
||||
};
|
||||
|
||||
|
||||
namespace StringFormat
|
||||
{
|
||||
enum
|
||||
{
|
||||
// Format specification flags
|
||||
F_MINUS = 1,
|
||||
F_PLUS = 2,
|
||||
F_ZERO = 4,
|
||||
F_BLANK = 8,
|
||||
F_HASH = 16,
|
||||
|
||||
F_SIGNED = 32,
|
||||
F_NEGATIVE = 64,
|
||||
F_ZEROVALUE = 128,
|
||||
F_FPT = 256,
|
||||
|
||||
// Format specification size prefixes
|
||||
F_HALFHALF = 0x1000, // hh
|
||||
F_HALF = 0x2000, // h
|
||||
F_LONG = 0x3000, // l
|
||||
F_LONGLONG = 0x4000, // ll or I64
|
||||
F_BIGI = 0x5000, // I
|
||||
F_PTRDIFF = 0x6000, // t
|
||||
F_SIZE = 0x7000, // z
|
||||
};
|
||||
typedef int (*OutputFunc)(void *data, const char *str, int len);
|
||||
|
||||
int VWorker (OutputFunc output, void *outputData, const char *fmt, va_list arglist);
|
||||
int Worker (OutputFunc output, void *outputData, const char *fmt, ...);
|
||||
};
|
||||
|
||||
#undef PRINTFISH
|
||||
|
||||
// Hash FStrings on their contents. (used by TMap)
|
||||
#include "superfasthash.h"
|
||||
|
||||
template<> struct THashTraits<FString>
|
||||
{
|
||||
hash_t Hash(const FString &key) { return (hash_t)SuperFastHash(key.GetChars(), key.Len()); }
|
||||
// Compares two keys, returning zero if they are the same.
|
||||
int Compare(const FString &left, const FString &right) { return left.Compare(right); }
|
||||
};
|
||||
|
||||
struct StringNoCaseHashTraits
|
||||
{
|
||||
hash_t Hash(const FString& key) { return (hash_t)SuperFastHashI(key.GetChars(), key.Len()); }
|
||||
// Compares two keys, returning zero if they are the same.
|
||||
int Compare(const FString& left, const FString& right) { return left.CompareNoCase(right); }
|
||||
};
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue