darin%meer.net ed54e4945c vtable_hide
git-svn-id: svn://10.0.0.236/trunk@149976 18797224-902f-48f8-a5cc-f745e15eee43
2003-12-03 07:50:05 +00:00

515 lines
14 KiB
C++

// vim:set ts=2 sw=2 et cindent:
#ifndef nsStrRef_h__
#define nsStrRef_h__
#include "types.h" // XXX temporary
#include "nsCharTraits.h"
class nsStrRef;
class nsStrDependentRef;
class nsStrAutoRef;
class nsStrFragment;
class nsStrFragmentTuple;
//-----------------------------------------------------------------------------
// container for an immutable string fragment, which is not necessarily
// null-terminated.
class nsStrFragment
{
public:
typedef NS_CHAR char_type;
typedef nsStrFragment self_type;
typedef nsCharTraits<char_type> char_traits;
typedef char_traits::comparator_func comparator_func;
nsStrFragment()
: mData(NS_CONST_CAST(char_type *, char_traits::empty_string))
, mLength(0) {}
nsStrFragment(const char_type *data, PRUint32 length)
: mData(NS_CONST_CAST(char_type *, data)), mLength(length) {}
// default copy constructor is appropriate
const char_type *get() const { return mData; }
PRUint32 Length() const { return mLength; }
PRBool IsEmpty() const { return mLength == 0; }
// character access
char_type First() const { return mData[0]; }
char_type Last() const;
PRUint32 CountChar(char_type c) const;
PRInt32 FindChar(char_type c, PRUint32 offset = 0) const;
// comparison
PRBool Equals(const self_type &ref) const;
PRBool Equals(const self_type &ref, comparator_func c) const;
PRInt32 CompareTo(const self_type &ref) const;
PRInt32 CompareTo(const self_type &ref, comparator_func c) const;
// returns true if this fragment is dependent on (i.e., overlapping with)
// the given char sequence.
PRBool IsDependentOn(const char_type *start, const char_type *end) const
{ return (mData >= start) && (mData < end); }
// XXX more functions...
protected:
// helper constructor for subclasses
nsStrFragment(char_type *data)
: mData(data) {}
nsStrFragment(char_type *data, PRUint32 length)
: mData(data), mLength(length) {}
// mData is non-const in this class since subclasses may manipulate it.
char_type *mData;
PRUint32 mLength;
};
//-----------------------------------------------------------------------------
// container for a null-terminated, immutable string of characters. since the
// string data is immutable, this class permits sharing of the underyling
// string data between threads. assignment between nsStrRef instances is
// optimized to avoid copying.
class nsStrRef : public nsStrFragment
{
public:
typedef nsStrRef self_type;
typedef nsStrFragment fragment_type;
typedef nsStrFragmentTuple fragment_tuple_type;
~nsStrRef();
// constructors
nsStrRef()
: nsStrFragment(), mFlags(F_DEPEND) {}
nsStrRef(const char_type *data, PRUint32 dataLen = PR_UINT32_MAX)
: nsStrFragment(nsnull) { Assign(data, dataLen); }
explicit
nsStrRef(const self_type &ref)
: nsStrFragment(nsnull) { Assign(ref); }
explicit
nsStrRef(const fragment_type &frag)
: nsStrFragment(nsnull) { Assign(frag); }
explicit
nsStrRef(const fragment_tuple_type &tuple)
: nsStrFragment(nsnull) { Assign(tuple); }
// adopt given null-terminated raw string
void Adopt(char_type *data, PRUint32 dataLen = PR_UINT32_MAX);
// assign into string reference
void Assign(const char_type c)
{ Assign(&c, 1); }
void Assign(const char_type *data, PRUint32 dataLen = PR_UINT32_MAX);
void Assign(const self_type &ref);
void Assign(const fragment_type &frag)
{ Assign(frag.get(), frag.Length()); }
void Assign(const fragment_tuple_type &tuple);
// assignment operators
self_type &operator=(const self_type &ref)
{ Assign(ref); return *this; }
self_type &operator=(const fragment_type &frag)
{ Assign(frag); return *this; }
self_type &operator=(const fragment_tuple_type &tuple)
{ Assign(tuple); return *this; }
// support for voiding a string
PRBool IsVoid() const { return mFlags & F_ISVOID; }
void SetIsVoid(PRBool);
protected:
// helper constructor for subclasses
nsStrRef(char_type *data, PRUint32 length, PRUint32 flags)
: nsStrFragment(data, length), mFlags(flags) {}
void ReleaseData();
enum
{
F_DEPEND = 0x1, // if set, then we do not own mData
F_SHARED = 0x2, // if set, then mData can be shared
F_ISVOID = 0x4 // if set, then the string is void
};
PRUint32 mFlags;
PRUint32 mCapacity;
};
//-----------------------------------------------------------------------------
// container for a null-terminated, immutable string of characters that is
// not owned by the container. this class is designed to be used as a wrapper
// around raw string literals so as to avoid copying the string literal.
class nsStrDependentRef : public nsStrRef
{
public:
typedef nsStrDependentRef self_type;
// constructors
explicit
nsStrDependentRef(const char_type *data)
{ mFlags = F_DEPEND; Rebind(data); }
nsStrDependentRef(const char_type *data, PRUint32 length)
{ mFlags = F_DEPEND; Rebind(data, length); }
nsStrDependentRef(const char_type *start, const char_type *end)
{ mFlags = F_DEPEND; Rebind(start, end); }
void Rebind(const char_type *data)
{ Rebind(data, char_traits::length_of(data)); }
void Rebind(const char_type *data, PRUint32 length)
{
NS_ASSERTION(data,
"nsStrDependentRef must wrap a non-NULL buffer");
NS_ASSERTION(!data[length],
"nsStrDependentRef must wrap only null-terminated buffer");
mData = NS_CONST_CAST(char_type *, data);
mLength = length;
}
void Rebind(const char_type *start, const char_type *end)
{ Rebind(start, end - start); }
private:
// NOT TO BE IMPLEMENTED
void operator=(const self_type &);
};
#define NS_STR_NAMED_LITERAL(name, val) nsStrDependentRef name(val, sizeof(val)-1)
#define NS_STR_LITERAL(val) nsStrDependentRef(val, sizeof(val)-1)
//-----------------------------------------------------------------------------
// substring helpers
inline const nsStrFragment
Substring(const nsStrFragment &frag, PRUint32 offset, PRUint32 length)
{
return nsStrFragment(frag.get() + offset, length);
}
inline const nsStrFragment
Substring(const NS_CHAR *data, PRUint32 length)
{
return nsStrFragment(data, length);
}
inline const nsStrFragment
Substring(const NS_CHAR *start, const NS_CHAR *end)
{
return nsStrFragment(start, end - start);
}
inline const nsStrFragment
StringHead(const nsStrFragment &frag, PRUint32 length)
{
return nsStrFragment(frag.get(), length);
}
inline const nsStrFragment
StringTail(const nsStrFragment &frag, PRUint32 length)
{
return nsStrFragment(frag.get() + frag.Length() - length, length);
}
//-----------------------------------------------------------------------------
// the fragment tuple represents a concatenation of string fragments.
class nsStrFragmentTuple
{
public:
typedef NS_CHAR char_type;
typedef nsCharTraits<char_type> char_traits;
nsStrFragmentTuple(const nsStrFragment &a, const nsStrFragment &b)
: mHead(nsnull)
, mFragA(a)
, mFragB(b) {}
nsStrFragmentTuple(const nsStrFragmentTuple &head, const nsStrFragment &frag)
: mHead(&head)
, mFragA(frag) // this fragment is ignored when head != null
, mFragB(frag)
{}
// computes the aggregate string length
PRUint32 Length() const;
// writes the aggregate string to the given buffer. bufLen is assumed to
// be equal to or greater than the value returned by the Length() method.
// the string written to |buf| is not null-terminated.
void WriteTo(char_type *buf, PRUint32 bufLen) const;
// returns true if this tuple is dependent on (i.e., overlapping with)
// the given char sequence.
PRBool IsDependentOn(const char_type *start, const char_type *end) const;
protected:
const nsStrFragmentTuple *mHead;
const nsStrFragment &mFragA;
const nsStrFragment &mFragB;
};
inline const nsStrFragmentTuple
operator+(const nsStrFragment &a, const nsStrFragment &b)
{
return nsStrFragmentTuple(a, b);
}
inline const nsStrFragmentTuple
operator+(const nsStrFragmentTuple &a, const nsStrFragment &b)
{
return nsStrFragmentTuple(a, b);
}
//-----------------------------------------------------------------------------
#if 0
// a container for a null-terminated, mutable string buffer. this class
// provides high-level string editing functions.
class nsStrBuf : public nsStrRef
{
public:
typedef nsStrRef ref_type;
typedef nsStrBuf self_type;
// constructors
nsStrBuf()
: nsStrRef(), mCapacity(0) {}
explicit
nsStrBuf(const char_type *data)
: nsStrRef(), mCapacity(0) { Assign(data); }
nsStrBuf(const char_type *data, PRUint32 dataLen)
: nsStrRef(), mCapacity(0) { Assign(data, dataLen); }
explicit
nsStrBuf(const ref_type &ref)
: nsStrRef(), mCapacity(0) { Assign(ref); }
explicit
nsStrBuf(const fragment_type &frag)
: nsStrRef(), mCapacity(0) { Assign(frag); }
explicit
nsStrBuf(const fragment_tuple_type &tuple)
: nsStrRef(), mCapacity(0) { Assign(tuple); }
// assign into string buffer
void Assign(const char_type c)
{ Assign(&c, 1); }
void Assign(const char_type *data, PRUint32 dataLen = PR_UINT32_MAX);
void Assign(const ref_type &ref);
void Assign(const fragment_type &frag);
void Assign(const fragment_tuple_type &tuple);
// assignment operators
self_type &operator=(const self_type &buf)
{ Assign(buf); return *this; }
self_type &operator=(const ref_type &ref)
{ Assign(ref); return *this; }
self_type &operator=(const fragment_type &frag)
{ Assign(frag); return *this; }
self_type &operator=(const fragment_tuple_type &tuple)
{ Assign(tuple); return *this; }
// replace part of string buffer
void Replace(PRUint32 cutOffset, PRUint32 cutLength, char_type c)
{ Replace(cutOffset, cutLength, &c, 1); }
void Replace(PRUint32 cutOffset, PRUint32 cutLength,
const char_type *data, PRUint32 dataLen = PR_UINT32_MAX);
void Replace(PRUint32 cutOffset, PRUint32 cutLength,
const fragment_type &frag);
void Replace(PRUint32 cutOffset, PRUint32 cutLength,
const fragment_tuple_type &tuple);
// append to string buffer
void Append(char_type c)
{ Replace(mLength, 0, &c, 1); }
void Append(const char_type *data, PRUint32 dataLen = PR_UINT32_MAX)
{ Replace(mLength, 0, data, dataLen); }
void Append(const fragment_type &frag)
{ Replace(mLength, 0, frag); }
void Append(const fragment_tuple_type &tuple)
{ Replace(mLength, 0, tuple); }
self_type &operator+=(char_type c)
{ Append(c); return *this; }
self_type &operator+=(const char_type *data)
{ Append(data); return *this; }
self_type &operator+=(const fragment_type &frag)
{ Append(frag); return *this; }
self_type &operator+=(const fragment_tuple_type &tuple)
{ Append(tuple); return *this; }
// insert into string buffer
void Insert(PRUint32 offset, char_type c)
{ Replace(offset, 0, &c, 1); }
void Insert(PRUint32 offset, const char_type *data,
PRUint32 dataLen = PR_UINT32_MAX)
{ Replace(offset, 0, data, dataLen); }
void Insert(PRUint32 offset, const fragment_type &frag)
{ Replace(offset, 0, frag); }
void Insert(PRUint32 offset, const fragment_tuple_type &tuple)
{ Replace(offset, 0, tuple); }
// cut out section of string buffer
void Cut(PRUint32 cutOffset, PRUint32 cutLength)
{ Replace(cutOffset, cutLength,
nsStrFragment(char_traits::empty_string, PRUint32(0))); }
void SetCapacity(PRUint32 capacity)
{ EnsureCapacity(capacity, PR_TRUE); }
void SetLength(PRUint32 length);
void Truncate(PRUint32 length)
{
NS_ASSERTION(length <= mLength, "|Trunate()| cannot make a string longer");
SetLength(length);
}
protected:
// helper constructor for subclasses
nsStrBuf(char_type *data, PRUint32 length, PRUint32 flags, PRUint32 capacity)
: nsStrRef(data, length, flags), mCapacity(capacity) {}
PRBool EnsureCapacity(PRUint32 capacity, PRBool preserveData);
// additional values for mFlags
enum
{
F_CAPACITYSET = 0x10 // if set, then mCapacity applies to mData
};
// holds the current size of the buffer at mData
PRUint32 mCapacity;
};
#endif
//-----------------------------------------------------------------------------
// subclass of nsStrBuf that makes use of fixed storage for small strings.
// this class is designed to be allocated on the stack.
class nsStrAutoBuf : public nsStrBuf
{
public:
typedef nsStrRef ref_type;
typedef nsStrBuf self_type;
// constructors
nsStrAutoBuf()
: nsStrBuf(mFixed, 0, F_DEPEND | F_CAPACITYSET, sizeof(mFixed))
{ mFixed[0] = char_type(0); }
explicit
nsStrAutoBuf(const char_type *data)
: nsStrBuf(mFixed, 0, F_DEPEND | F_CAPACITYSET, sizeof(mFixed))
{ Assign(data); }
nsStrAutoBuf(const char_type *data, PRUint32 dataLen)
: nsStrBuf(mFixed, 0, F_DEPEND | F_CAPACITYSET, sizeof(mFixed))
{ Assign(data, dataLen); }
explicit
nsStrAutoBuf(const ref_type &ref)
: nsStrBuf(mFixed, 0, F_DEPEND | F_CAPACITYSET, sizeof(mFixed))
{ Assign(ref); }
explicit
nsStrAutoBuf(const fragment_type &frag)
: nsStrBuf(mFixed, 0, F_DEPEND | F_CAPACITYSET, sizeof(mFixed))
{ Assign(frag); }
explicit
nsStrAutoBuf(const fragment_tuple_type &tuple)
: nsStrBuf(mFixed, 0, F_DEPEND | F_CAPACITYSET, sizeof(mFixed))
{ Assign(tuple); }
// assign
self_type &operator=(const self_type &buf)
{ Assign(buf); return *this; }
self_type &operator=(const ref_type &ref)
{ Assign(ref); return *this; }
self_type &operator=(const fragment_type &frag)
{ Assign(frag); return *this; }
self_type &operator=(const fragment_tuple_type &tuple)
{ Assign(tuple); return *this; }
protected:
char_type mFixed[64]; // this is in use if F_DEPEND is set.
};
//-----------------------------------------------------------------------------
#endif // nsStrRef_h__