vtable_hide

git-svn-id: svn://10.0.0.236/trunk@149976 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
darin%meer.net 2003-12-03 07:50:05 +00:00
parent 8cf0dd6dee
commit ed54e4945c
21 changed files with 1588 additions and 0 deletions

View File

@ -0,0 +1,8 @@
CXXFLAGS = -g -Os -Wall -fno-exceptions
#CXXFLAGS = -g -Wall -fno-exceptions
test: test.o nsStrRef.o nsCharTraits.o
nsStrRef.o: nsStrRef.cpp nsStrRef.h nsCharTraits.h types.h Makefile
nsCharTraits: nsCharTraits.cpp nsCharTraits.h types.h Makefile
test.o: test.cpp nsStrRef.h nsCharTraits.h types.h Makefile
clean:
rm -f *.o test

View File

@ -0,0 +1,3 @@
#include "nsCharTraits.h"
const char *nsCharTraits<char>::empty_string = "";

View File

@ -0,0 +1,40 @@
/* vim:set ts=2 sw=2 et cindent: */
#ifndef nsCharTraits_h__
#define nsCharTraits_h__
#include "types.h" // XXX temporary
#include <string.h>
template <class T> struct nsCharTraits {};
NS_SPECIALIZE_TEMPLATE
struct nsCharTraits<char>
{
public:
typedef char char_type;
typedef PRInt32 (* comparator_func)
(const char_type *a, const char_type *b, int n);
static const char_type *empty_string;
static PRInt32 case_sensitive_comparator(const char_type *a,
const char_type *b, int n)
{ return (PRInt32) memcmp(a, b, n); }
static PRUint32 length_of(const char_type *data)
{ return (PRUint32) ::strlen(data); }
static void copy(char_type *dest, const char_type *src, PRUint32 len)
{ ::memcpy(dest, src, len); }
static void move(char_type *dest, const char_type *src, PRUint32 len)
{ ::memmove(dest, src, len); }
static const char_type *find_char(const char_type *start,
const char_type *end,
char_type c)
{ return (const char_type *) ::memchr(start, c, end - start); }
};
#endif // nsCharTraits_h__

View File

@ -0,0 +1,543 @@
// vim:set ts=2 sw=2 et cindent:
#include <stdlib.h>
#include "nsStrRef.h"
//-----------------------------------------------------------------------------
// nsStrFragment methods:
nsStrFragment::char_type
nsStrFragment::Last() const
{
char_type last;
if (mLength > 0)
{
last = mData[mLength - 1];
}
else
{
NS_ERROR("|Last()| on an empty string");
last = char_type(0); // BOGUS
}
return last;
}
PRUint32
nsStrFragment::CountChar(char_type c) const
{
PRUint32 result = 0;
const char_type *start = mData;
const char_type *end = mData + mLength;
while (start && start != end)
{
start = char_traits::find_char(start, end, c);
if (start)
{
++result;
++start;
}
}
return result;
}
PRInt32
nsStrFragment::FindChar(char_type c, PRUint32 offset) const
{
const char_type *p = char_traits::find_char(mData + offset,
mData + mLength, c);
if (p)
return p - mData;
return -1; // XXX kNotFound
}
PRBool
nsStrFragment::Equals(const self_type &ref) const
{
return mLength == ref.mLength &&
char_traits::case_sensitive_comparator(mData, ref.mData, mLength) == 0;
}
PRBool
nsStrFragment::Equals(const self_type &ref, comparator_func comp) const
{
return mLength == ref.mLength &&
comp(mData, ref.mData, mLength) == 0;
}
PRInt32
nsStrFragment::CompareTo(const self_type &ref) const
{
if (mLength > ref.mLength)
return 1;
if (mLength < ref.mLength)
return -1;
return char_traits::case_sensitive_comparator(mData, ref.mData, mLength);
}
PRInt32
nsStrFragment::CompareTo(const self_type &ref, comparator_func comp) const
{
if (mLength > ref.mLength)
return 1;
if (mLength < ref.mLength)
return -1;
return comp(mData, ref.mData, mLength);
}
//-----------------------------------------------------------------------------
// reference counted buffer methods:
inline void StrIncrementRef(void *data)
{
PRInt32 *buf = ((PRInt32 *) data) - 1;
PR_AtomicIncrement(buf);
}
inline void StrDecrementRef(void *data)
{
PRInt32 *buf = ((PRInt32 *) data) - 1;
if (PR_AtomicDecrement(buf) == 0)
{
printf(">>> calling free on %p [%s]\n", data, (const char *) data);
free(buf);
}
}
inline void *StrAllocateSharedBuf(size_t n)
{
PRInt32 *buf = (PRInt32 *) malloc(n + sizeof(PRUint32));
if (buf)
{
buf[0] = 1;
buf++;
}
return buf;
}
//-----------------------------------------------------------------------------
// nsStrRef methods:
nsStrRef::~nsStrRef()
{
if (mData)
ReleaseData();
}
void
nsStrRef::ReleaseData()
{
NS_ASSERTION(mData, "should not call ReleaseData with null mData");
if (!(mFlags & F_DEPEND))
{
if (mFlags & F_SHARED)
{
StrDecrementRef(mData);
}
else
{
printf(">>> calling free on %p [%s]\n", mData, mData);
free(mData);
}
}
}
void
nsStrRef::Adopt(char_type *data, PRUint32 dataLen)
{
if (mData)
ReleaseData();
if (dataLen == PR_UINT32_MAX)
dataLen = char_traits::length_of(data);
mData = data;
mLength = dataLen;
mFlags = 0;
}
void
nsStrRef::Assign(const char_type *data, PRUint32 dataLen)
{
if (dataLen == PR_UINT32_MAX)
dataLen = char_traits::length_of(data);
// do not release mData until we've created the new buffer. this allows for
// the case where data might reference part of mData.
char_type *buf =
(char_type *) StrAllocateSharedBuf((dataLen + 1) * sizeof(char_type));
if (buf)
{
char_traits::copy(buf, data, dataLen);
buf[dataLen] = 0;
// okay, now we can safely release mData
if (mData)
ReleaseData();
mData = buf;
mLength = dataLen;
mFlags = F_SHARED;
printf(">>> new buffer at %p [%s]\n", mData, mData);
}
}
void
nsStrRef::Assign(const self_type &ref)
{
// self-assign is a no-op
if (this == &ref)
return;
if (ref.mFlags & F_SHARED)
{
// since ref.mData is reference counted, we can safely release our mData.
ReleaseData();
mData = ref.mData;
mLength = ref.mLength;
mFlags = ref.mFlags;
StrIncrementRef(mData);
}
else
Assign(ref.mData, ref.mLength);
}
void
nsStrRef::Assign(const fragment_tuple_type &tuple)
{
PRUint32 len = tuple.Length();
char_type *buf =
(char_type *) StrAllocateSharedBuf((len + 1) * sizeof(char_type));
if (buf)
{
tuple.WriteTo(buf, len);
buf[len] = char_type(0);
ReleaseData();
mData = buf;
mLength = len;
mFlags = nsStrRef::F_SHARED;
}
}
void
nsStrRef::SetIsVoid(PRBool val)
{
if (val)
{
ReleaseData();
mData = NS_CONST_CAST(char_type *, char_traits::empty_string);
mLength = 0;
mFlags = F_DEPEND | F_ISVOID;
}
else
{
mFlags &= ~F_ISVOID;
}
}
//-----------------------------------------------------------------------------
// nsStrFragmentTuple methods:
PRUint32
nsStrFragmentTuple::Length() const
{
//
// fragments are enumerated right to left
//
PRUint32 len = mFragB.Length();
if (mHead)
len += mHead->Length();
else
len += mFragA.Length();
return len;
}
void
nsStrFragmentTuple::WriteTo(char_type *buf, PRUint32 end) const
{
// we need to write out data into buf, ending at end. so our data
// needs to preceed |end| exactly. we trust that the buffer was
// properly sized!
char_traits::copy(buf + end - mFragB.Length(), mFragB.get(), mFragB.Length());
end -= mFragB.Length();
if (mHead)
mHead->WriteTo(buf, end);
else
char_traits::copy(buf + end - mFragA.Length(), mFragA.get(), mFragA.Length());
}
PRBool
nsStrFragmentTuple::IsDependentOn(const char_type *start,
const char_type *end) const
{
//
// fragments are enumerated right to left
//
PRBool dependent = mFragB.IsDependentOn(start, end);
if (!dependent)
{
if (mHead)
dependent = mHead->IsDependentOn(start, end);
else
dependent = mFragA.IsDependentOn(start ,end);
}
return dependent;
}
//-----------------------------------------------------------------------------
// nsStrBuf methods:
void
nsStrBuf::Assign(const char_type *data, PRUint32 dataLen)
{
if (dataLen == PR_UINT32_MAX)
dataLen = char_traits::length_of(data);
Assign(nsStrFragment(data, dataLen));
}
void
nsStrBuf::Assign(const ref_type &ref)
{
// self-assign is a no-op
if (this == &ref)
return;
// avoid copying if possible...
// XXX for some strange reason GCC 3.2.2 requires this cast
if (NS_STATIC_CAST(const self_type &, ref).mFlags & F_SHARED)
nsStrRef::Assign(ref);
else
Assign(NS_STATIC_CAST(const fragment_type &, ref));
}
void
nsStrBuf::Assign(const fragment_type &frag)
{
// self-assign is a no-op
if (this == &frag)
return;
PRUint32 len = frag.Length();
// check if the fragment depends on mData
if (frag.IsDependentOn(mData, mData + mLength))
{
nsStrAutoBuf temp(frag);
Assign(temp);
return;
}
if (EnsureCapacity(len + 1, PR_FALSE))
{
char_traits::copy(mData, frag.get(), len);
mData[len] = char_type(0);
mLength = len;
}
}
void
nsStrBuf::Assign(const fragment_tuple_type &tuple)
{
PRUint32 len = tuple.Length();
printf("+++ %s [f=0x%x c=%u len=%u]\n", __PRETTY_FUNCTION__, mFlags, mCapacity, len);
// check if the fragment tuple depends on mData
if (tuple.IsDependentOn(mData, mData + mLength))
{
nsStrAutoBuf temp(tuple);
Assign(temp);
return;
}
if (EnsureCapacity(len + 1, PR_FALSE))
{
tuple.WriteTo(mData, len);
mData[len] = char_type(0);
mLength = len;
}
}
void
nsStrBuf::Replace(PRUint32 cutOffset, PRUint32 cutLength, const char_type *data, PRUint32 dataLen)
{
if (dataLen == PR_UINT32_MAX)
dataLen = char_traits::length_of(data);
Replace(cutOffset, cutLength, nsStrFragment(data, dataLen));
}
void
nsStrBuf::Replace(PRUint32 cutOffset, PRUint32 cutLength,
const fragment_type &frag)
{
// check if the fragment depends on mData
if (frag.IsDependentOn(mData, mData + mLength))
{
nsStrAutoBuf temp(frag);
Replace(cutOffset, cutLength, temp);
return;
}
PRUint32 fragLen = frag.Length();
PRUint32 newLen = mLength - cutLength + fragLen;
if (EnsureCapacity(newLen + 1, PR_TRUE))
{
// make space for new substring. may require that we move part
// of the existing string.
if (fragLen != cutLength && cutOffset + cutLength < mLength)
{
PRUint32 from = cutOffset + cutLength;
PRUint32 fromLen = mLength - from;
PRUint32 to = cutOffset + fragLen;
char_traits::move(mData + to, mData + from, fromLen);
}
if (fragLen)
char_traits::copy(mData + cutOffset, frag.get(), fragLen);
mData[newLen] = char_type(0);
mLength = newLen;
}
}
void
nsStrBuf::Replace(PRUint32 cutOffset, PRUint32 cutLength,
const fragment_tuple_type &tuple)
{
// check if the fragment depends on mData
if (tuple.IsDependentOn(mData, mData + mLength))
{
nsStrAutoBuf temp(tuple);
Replace(cutOffset, cutLength, temp);
return;
}
PRUint32 tupleLen = tuple.Length();
PRUint32 newLen = mLength - cutLength + tupleLen;
if (EnsureCapacity(newLen + 1, PR_TRUE))
{
// make space for new substring. may require that we move part
// of the existing string.
if (tupleLen != cutLength && cutOffset + cutLength < mLength)
{
PRUint32 from = cutOffset + cutLength;
PRUint32 fromLen = mLength - from;
PRUint32 to = cutOffset + tupleLen;
char_traits::move(mData + to, mData + from, fromLen);
}
if (tupleLen)
tuple.WriteTo(mData + cutOffset, tupleLen);
mData[newLen] = char_type(0);
mLength = newLen;
}
}
void
nsStrBuf::SetLength(PRUint32 len)
{
EnsureCapacity(len + 1, PR_TRUE);
mData[len] = 0;
mLength = len;
}
PRBool
nsStrBuf::EnsureCapacity(PRUint32 capacity, PRBool preserveData)
{
// EnsureCapacity is called in preparation for writing. So, if we have a
// reference to a shared buffer, then we need to go ahead and drop that
// shared reference.
if (mFlags & F_SHARED)
{
char *buf = (char *) malloc(capacity * sizeof(char_type));
if (!buf)
return PR_FALSE;
if (preserveData)
{
PRUint32 maxLength = capacity - 1;
if (mLength > maxLength)
mLength = maxLength;
char_traits::copy(buf, mData, mLength);
buf[mLength] = char_type(0);
}
ReleaseData();
mData = buf;
mCapacity = capacity;
mFlags = F_CAPACITYSET;
}
else
{
if (!(mFlags & F_CAPACITYSET))
{
// maybe someone called nsStrRef::Adopt
mCapacity = mLength + 1;
}
if (capacity > mCapacity)
{
printf(">>> increasing capacity\n");
// use doubling algorithm when forced to increase available capacity
PRUint32 temp = mCapacity;
while (temp < capacity)
temp <<= 1;
capacity = temp;
char *buf;
if (mFlags & F_DEPEND)
{
// we cannot realloc the existing buffer because we do not own it.
buf = (char *) malloc(capacity * sizeof(char_type));
if (!buf)
return PR_FALSE;
if (preserveData)
char_traits::copy(buf, mData, mLength + 1);
mFlags &= ~F_DEPEND;
}
else
{
buf = (char *) realloc(mData, capacity * sizeof(char_type));
if (!buf)
return PR_FALSE;
}
mData = buf;
mCapacity = capacity;
printf(" new capacity = %u\n", mCapacity);
}
}
return PR_TRUE;
}

View File

@ -0,0 +1,514 @@
// 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__

View File

@ -0,0 +1,62 @@
#include <stdio.h>
#include "nsStrRef.h"
void func(const char *p)
{
printf("--%s--\n", p);
}
void concat_and_print(const nsStrRef &a, const nsStrRef &b)
{
nsStrRef r(a + b);
printf("%s\n", r.get());
}
int main()
{
nsStrRef a("howdy");
NS_STR_NAMED_LITERAL(b, "howdy");
printf("%s %s %d\n", a.get(), b.get(), a.Equals(b));
nsStrRef d;
d.Assign('x');
printf("%s\n", d.get());
nsStrRef r(Substring(a, 1, 3));
printf("%s\n", r.get());
nsStrDependentRef c("foopity");
r = a + nsStrRef("/balance/") + b + c + nsStrDependentRef("bob");
printf("%s\n", r.get());
func(nsStrRef("xyz").get());
nsStrDependentRef aa("foo"), bb("bar");
concat_and_print(aa, bb);
nsStrAutoBuf a_buf;
a_buf = Substring(aa, 1, 2) + r;
printf("1:%s\n", a_buf.get());
a_buf = NS_STR_LITERAL("$w$") + a_buf + NS_STR_LITERAL("$you$");
printf("2:%s\n", a_buf.get());
a_buf.Append(NS_STR_LITERAL("--") + r + NS_STR_LITERAL("--") + r);
printf("3:%s\n", a_buf.get());
a_buf.Insert(10, "((xyz))");
printf("4:%s\n", a_buf.get());
/*
nsStrRef &a_ref = a_buf;
a_ref.Assign(NS_STR_LITERAL("one day on the road"));
*/
a_buf += aa + NS_STR_LITERAL("[[ ") + a_buf + NS_STR_LITERAL(" ]]") + c;
printf("5:%s\n", a_buf.get());
a_buf.Replace(0, 5, a);
printf("6:%s\n", a_buf.get());
return 0;
}

28
vtable_hide/string/tt.cc Normal file
View File

@ -0,0 +1,28 @@
class A
{
public:
A(int x, int y, int z)
: _x(x), _y(y), _z(z) {}
private:
int _x, _y, _z;
};
class B
{
public:
B(int x, int y, int z)
{ _x = x;
_z = z;
_y = y;
}
private:
int _x, _y, _z;
};
int main()
{
A a(1, 2, 3);
B b(1, 2, 3);
return 0;
}

View File

@ -0,0 +1,28 @@
/* vim:set ts=2 sw=2 et cindent: */
#ifndef str_types_h__
#define str_types_h__
/* -------------------------------------------------------------------------- */
#include <stdio.h>
typedef int PRInt32;
typedef unsigned int PRUint32;
typedef unsigned int PRBool;
#define PR_TRUE 1
#define PR_FALSE 0
typedef char NS_CHAR;
#define NS_CHAR_SIZE sizeof(NS_CHAR)
#define NS_COM
#define NS_ASSERTION(x, s) if (!(x)) printf("### ASSERTION [%s]: %s\n", # x, s)
#define NS_ERROR(s) printf("### ERROR: %s\n", s)
#define PR_MIN(x,y) ((x) < (y) ? (x) : (y))
#define NS_CONST_CAST(x,y) const_cast<x>(y)
#define NS_STATIC_CAST(x,y) static_cast<x>(y)
#define nsnull 0
#define NS_SPECIALIZE_TEMPLATE template <>
#define PR_AtomicIncrement(x) (++(*(x)))
#define PR_AtomicDecrement(x) (--(*(x)))
#define PR_UINT32_MAX PRUint32(-1)
/* -------------------------------------------------------------------------- */
#endif

View File

@ -0,0 +1,13 @@
# vim:set ts=8 sw=8 noet:
all: libfoo.so libfoo++.so test test++
libfoo.so: libfoo.c Makefile
gcc -g -fPIC -shared $< -o $@
libfoo++.so: libfoo++.cc Makefile
gcc -g -fPIC -fno-exceptions -shared $< -o $@ -lsupc++
test: test.cc libfoo.h Makefile
gcc -g -fno-exceptions $< -o $@ -L. -lfoo -lsupc++
test++: test.cc libfoo.h Makefile
gcc -g -fno-exceptions $< -o $@ -L. -lfoo++ -lsupc++
clean:
rm -f test libfoo.so

View File

@ -0,0 +1,41 @@
#include <stdio.h>
#include <stdlib.h>
class Foo
{
public:
static Foo sFoo;
Foo() {}
virtual ~Foo()
{
printf("~Foo [this=%p]\n", this);
}
virtual int meth1()
{
if ( *((int *) this) == *((int *) &sFoo) )
printf("vptrs match\n");
printf("meth1 [this=%p]\n", this);
}
virtual int meth2(const char *s)
{ printf("meth2 [this=%p s=\"%s\"]\n", this, s); }
virtual int meth3(int x, const char *s)
{ printf("meth3 [this=%p x=%d s=\"%s\"]\n", this, x, s); }
virtual int meth4(int x, const char *s, char c)
{ printf("meth4 [this=%p x=%d s=\"%s\" c=%c]\n", this, x, s, c); }
};
Foo Foo::sFoo;
extern "C" Foo *
CreateFoo()
{
/*
Foo *f = (Foo *) malloc(sizeof(Foo));
new (f) Foo();
return f;
*/
return new Foo();
}

View File

@ -0,0 +1,65 @@
struct Foo;
struct FooMethods;
struct FooMethods
{
void (* dtor)(struct Foo * const);
int (* meth1)(struct Foo * const);
int (* meth2)(struct Foo *, const char *);
int (* meth3)(struct Foo *, int, const char *);
int (* meth4)(struct Foo *, int, const char *, char);
void (* dummy1)(struct Foo *);
void (* dummy2)(struct Foo *);
};
struct Foo
{
struct FooMethods *vptr;
int x;
};
static void foo_dtor(struct Foo * const self)
{
printf("foo_dtor [self=%p]\n", self);
}
static int foo_meth1(struct Foo *self)
{
printf("foo_meth1 [self=%p]\n", self);
}
static int foo_meth2(struct Foo *self, const char *s)
{
printf("foo_meth2 [self=%p s=\"%s\"]\n", self, s);
}
static int foo_meth3(struct Foo *self, int x, const char *s)
{
printf("foo_meth3 [self=%p x=%d s=\"%s\"]\n", self, x, s);
}
static int foo_meth4(struct Foo *self, int x, const char *s, char c)
{
printf("foo_meth4 [self=%p x=%d s=\"%s\" c=%c]\n", self, x, s, c);
}
static void foo_dummy(struct Foo *self)
{
printf("foo_dummy [self=%p]\n", self);
}
static struct FooMethods foo_methods = {
&foo_dtor,
&foo_dummy,
&foo_meth1,
&foo_meth2,
&foo_meth3,
&foo_meth4,
};
struct Foo *CreateFoo()
{
struct Foo *f = (struct Foo *) malloc(sizeof(struct Foo));
f->vptr = &foo_methods;
return f;
}

View File

@ -0,0 +1,18 @@
/* vim:set ts=2 sw=2 et cindent: */
#ifndef LIBFOO_H__
#define LIBFOO_H__
class Foo
{
public:
virtual ~Foo() { }
virtual int meth1() = 0;
virtual int meth2(const char *) = 0;
virtual int meth3(int, const char *) = 0;
virtual int meth4(int, const char *, char) = 0;
};
extern "C" Foo * CreateFoo();
#endif

BIN
vtable_hide/vtable_foo/test Executable file

Binary file not shown.

BIN
vtable_hide/vtable_foo/test++ Executable file

Binary file not shown.

View File

@ -0,0 +1,17 @@
#include <stdlib.h>
#include "libfoo.h"
int main()
{
Foo *f = CreateFoo();
if (f)
{
f->meth1();
f->meth2("hello");
f->meth3(10, "hello");
f->meth4(10, "hello", 'x');
f->~Foo();
// free(f);
}
return 0;
}

Binary file not shown.

View File

@ -0,0 +1,11 @@
# vim:set noet ts=4 sw=4:
all: test
shim.o: shim.cc shim.h inner.h Makefile
gcc -c -g -fno-exceptions $< -o $@
test.o: test.cc shim.h inner.h Makefile
gcc -c -g -fno-exceptions $< -o $@
test: test.o shim.o
gcc $^ -o $@ -lsupc++
clean:
rm -f *.o test

View File

@ -0,0 +1,12 @@
#ifndef inner_h__
#define inner_h__
class Inner
{
public:
virtual ~Inner() {}
virtual void foo(int x) = 0;
virtual void bar(int x, const char *s) = 0;
};
#endif

View File

@ -0,0 +1,98 @@
// vim:set cindent:
#include <stddef.h>
#include <stdio.h>
#include "shim.h"
#include "inner.h"
class InnerImpl : public Inner
{
public:
InnerImpl() {}
virtual ~InnerImpl()
{
printf("InnerImpl::~InnerImpl [this=%p]\n", this);
ShimDtor((Shim *) this);
}
virtual void foo(int x)
{
printf("InnerImpl::foo [this=%p x=%d]\n", this, x);
ShimFoo((Shim *) this, x);
}
virtual void bar(int x, const char *s)
{
printf("InnerImpl::bar [this=%p x=%d s=\"%s\"]\n", this, x, s);
ShimBar((Shim *) this, x, s);
}
};
// placement new
inline void *operator new(size_t size, Shim *s) { return s; }
static Shim
GetOurImpl()
{
Shim ourImpl;
new (&ourImpl) InnerImpl();
return ourImpl;
}
static Shim gOurImpl = GetOurImpl();
#define IS_EXTERNAL_IMPL(self) (self->vptr != gOurImpl.vptr)
void ShimCtor(Shim *self)
{
printf("ShimCtor [self=%p]\n", self);
new (self) InnerImpl();
/*
* initialize our members after placement new since sizeof InnerImpl
* may be bigger than sizeof(void *)
*/
self->data = 0;
self->length = 1;
self->flags = 2;
}
void ShimDtor(Shim *self)
{
printf("ShimDtor [self=%p]\n", self);
if (IS_EXTERNAL_IMPL(self))
{
((Inner *) self)->~Inner();
return;
}
printf(" ++ running our dtor!\n");
}
void ShimFoo(Shim *self, int x)
{
printf("ShimFoo [self=%p x=%d]\n", self, x);
if (IS_EXTERNAL_IMPL(self))
{
((Inner *) self)->foo(x);
return;
}
printf(" ++ running our foo!\n");
}
void ShimBar(Shim *self, int x, const char *s)
{
printf("ShimBar [self=%p x=%d s=\"%s\"]\n", self, x, s);
if (IS_EXTERNAL_IMPL(self))
{
((Inner *) self)->bar(x, s);
return;
}
printf(" ++ running our bar!\n");
}

View File

@ -0,0 +1,17 @@
#ifndef shim_h__
#define shim_h__
struct Shim
{
void *vptr;
char *data;
int length;
int flags;
};
void ShimCtor(Shim *);
void ShimDtor(Shim *);
void ShimFoo(Shim *, int x);
void ShimBar(Shim *, int x, const char *s);
#endif

View File

@ -0,0 +1,70 @@
// vim:set cindent:
#include <stdio.h>
#include "shim.h"
#include "inner.h"
class Outer
{
private:
Shim shim;
public:
Outer() { ShimCtor(&shim); }
~Outer() { ShimDtor(&shim); }
void foo(int x) { ShimFoo(&shim, x); }
void bar(int x, const char *s) { ShimBar(&shim, x,s); }
};
class ExtImpl : public Inner
{
public:
ExtImpl() {}
virtual ~ExtImpl()
{
printf(" -- ExtImpl::~ExtImpl [this=%p]\n", this);
}
virtual void foo(int x)
{
printf(" -- ExtImpl::foo [this=%p x=%d]\n", this, x);
}
virtual void bar(int x, const char *s)
{
printf(" -- ExtImpl::bar [this=%p x=%d s=\"%s\"]\n", this, x, s);
}
};
int main()
{
printf("\ntest use of our class directly:\n\n");
{
Outer outer;
outer.foo(10);
outer.bar(10, "hello");
}
printf("\n\ntest use of embedders class, interpreted as if it were our class:\n\n");
{
ExtImpl *ext = new ExtImpl();
Outer *outer = reinterpret_cast<Outer *>(ext);
outer->foo(5);
outer->bar(5, "world");
delete outer;
}
printf("\n\ntest use of our class, interpreted as if it were abstract class:\n\n");
{
Outer *outer = new Outer();
Inner *inner = reinterpret_cast<Inner *>(outer);
inner->foo(1);
inner->bar(1, "crazy");
delete inner;
}
printf("\n");
return 0;
}