vtable_hide
git-svn-id: svn://10.0.0.236/trunk@149976 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
8cf0dd6dee
commit
ed54e4945c
8
vtable_hide/string/Makefile
Normal file
8
vtable_hide/string/Makefile
Normal 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
|
||||
3
vtable_hide/string/nsCharTraits.cpp
Normal file
3
vtable_hide/string/nsCharTraits.cpp
Normal file
@ -0,0 +1,3 @@
|
||||
#include "nsCharTraits.h"
|
||||
|
||||
const char *nsCharTraits<char>::empty_string = "";
|
||||
40
vtable_hide/string/nsCharTraits.h
Normal file
40
vtable_hide/string/nsCharTraits.h
Normal 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__
|
||||
543
vtable_hide/string/nsStrRef.cpp
Normal file
543
vtable_hide/string/nsStrRef.cpp
Normal 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;
|
||||
}
|
||||
514
vtable_hide/string/nsStrRef.h
Normal file
514
vtable_hide/string/nsStrRef.h
Normal 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__
|
||||
62
vtable_hide/string/test.cpp
Normal file
62
vtable_hide/string/test.cpp
Normal 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
28
vtable_hide/string/tt.cc
Normal 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;
|
||||
}
|
||||
28
vtable_hide/string/types.h
Normal file
28
vtable_hide/string/types.h
Normal 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
|
||||
13
vtable_hide/vtable_foo/Makefile
Normal file
13
vtable_hide/vtable_foo/Makefile
Normal 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
|
||||
41
vtable_hide/vtable_foo/libfoo++.cc
Normal file
41
vtable_hide/vtable_foo/libfoo++.cc
Normal 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();
|
||||
}
|
||||
65
vtable_hide/vtable_foo/libfoo.c
Normal file
65
vtable_hide/vtable_foo/libfoo.c
Normal 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;
|
||||
}
|
||||
18
vtable_hide/vtable_foo/libfoo.h
Normal file
18
vtable_hide/vtable_foo/libfoo.h
Normal 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
BIN
vtable_hide/vtable_foo/test
Executable file
Binary file not shown.
BIN
vtable_hide/vtable_foo/test++
Executable file
BIN
vtable_hide/vtable_foo/test++
Executable file
Binary file not shown.
17
vtable_hide/vtable_foo/test.cc
Normal file
17
vtable_hide/vtable_foo/test.cc
Normal 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;
|
||||
}
|
||||
BIN
vtable_hide/vtable_hide.tar.gz
Normal file
BIN
vtable_hide/vtable_hide.tar.gz
Normal file
Binary file not shown.
11
vtable_hide/vtable_hide/Makefile
Normal file
11
vtable_hide/vtable_hide/Makefile
Normal 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
|
||||
12
vtable_hide/vtable_hide/inner.h
Normal file
12
vtable_hide/vtable_hide/inner.h
Normal 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
|
||||
98
vtable_hide/vtable_hide/shim.cc
Normal file
98
vtable_hide/vtable_hide/shim.cc
Normal 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");
|
||||
}
|
||||
17
vtable_hide/vtable_hide/shim.h
Normal file
17
vtable_hide/vtable_hide/shim.h
Normal 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
|
||||
70
vtable_hide/vtable_hide/test.cc
Normal file
70
vtable_hide/vtable_hide/test.cc
Normal 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;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user