added refcounting to wxCharBuffer to fix passing of wxCharBuffer to printf-like functions
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@55048 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -33,126 +33,155 @@ public:
|
|||||||
typedef T CharType;
|
typedef T CharType;
|
||||||
|
|
||||||
wxCharTypeBuffer(const CharType *str = NULL)
|
wxCharTypeBuffer(const CharType *str = NULL)
|
||||||
: m_str(str ? wxStrdup(str) : NULL),
|
|
||||||
m_owned(true)
|
|
||||||
{
|
{
|
||||||
|
if ( str )
|
||||||
|
m_data = new Data(wxStrdup(str));
|
||||||
|
else
|
||||||
|
m_data = &NullData;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxCharTypeBuffer(size_t len)
|
wxCharTypeBuffer(size_t len)
|
||||||
: m_str((CharType *)malloc((len + 1)*sizeof(CharType))),
|
|
||||||
m_owned(true)
|
|
||||||
{
|
{
|
||||||
m_str[len] = (CharType)0;
|
m_data = new Data((CharType *)malloc((len + 1)*sizeof(CharType)));
|
||||||
|
m_data->m_str[len] = (CharType)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const wxCharTypeBuffer CreateNonOwned(const CharType *str)
|
static const wxCharTypeBuffer CreateNonOwned(const CharType *str)
|
||||||
{
|
{
|
||||||
wxCharTypeBuffer buf;
|
wxCharTypeBuffer buf;
|
||||||
buf.m_str = wx_const_cast(CharType*, str);
|
if ( str )
|
||||||
buf.m_owned = false;
|
buf.m_data = new Data(wx_const_cast(CharType*, str), Data::NonOwned);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no need to check for NULL, free() does it */
|
|
||||||
~wxCharTypeBuffer()
|
~wxCharTypeBuffer()
|
||||||
{
|
{
|
||||||
if ( m_owned)
|
DecRef();
|
||||||
free(m_str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
CharType *release()
|
||||||
WARNING:
|
|
||||||
|
|
||||||
the copy ctor and assignment operators change the passed in object
|
|
||||||
even although it is declared as "const", so:
|
|
||||||
|
|
||||||
a) it shouldn't be really const
|
|
||||||
b) you shouldn't use it afterwards (or know that it was reset)
|
|
||||||
|
|
||||||
This is very ugly but is unfortunately needed to make the normal use
|
|
||||||
of wxCharTypeBuffer buffer objects possible and is very similar to what
|
|
||||||
std::auto_ptr<> does (as if it were an excuse...)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
because of the remark above, release() is declared const even if it
|
|
||||||
isn't really const
|
|
||||||
*/
|
|
||||||
CharType *release() const
|
|
||||||
{
|
{
|
||||||
wxASSERT_MSG( m_owned, _T("can't release non-owned buffer") );
|
if ( m_data == &NullData )
|
||||||
return DoRelease();
|
return NULL;
|
||||||
|
|
||||||
|
wxASSERT_MSG( m_data->m_owned, _T("can't release non-owned buffer") );
|
||||||
|
wxASSERT_MSG( m_data->m_ref == 1, _T("can't release shared buffer") );
|
||||||
|
|
||||||
|
CharType *p = m_data->m_str;
|
||||||
|
m_data->m_str = NULL;
|
||||||
|
DecRef();
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset()
|
void reset()
|
||||||
{
|
{
|
||||||
if ( m_owned )
|
DecRef();
|
||||||
free(m_str);
|
|
||||||
m_str = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wxCharTypeBuffer(const wxCharTypeBuffer& src)
|
wxCharTypeBuffer(const wxCharTypeBuffer& src)
|
||||||
{
|
{
|
||||||
CopyFrom(src);
|
m_data = src.m_data;
|
||||||
|
IncRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxCharTypeBuffer& operator=(const CharType *str)
|
wxCharTypeBuffer& operator=(const CharType *str)
|
||||||
{
|
{
|
||||||
if ( m_owned )
|
DecRef();
|
||||||
free(m_str);
|
|
||||||
m_str = str ? wxStrdup(str) : NULL;
|
if ( str )
|
||||||
m_owned = true;
|
m_data = new Data(wxStrdup(str));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxCharTypeBuffer& operator=(const wxCharTypeBuffer& src)
|
wxCharTypeBuffer& operator=(const wxCharTypeBuffer& src)
|
||||||
{
|
{
|
||||||
if (&src != this)
|
if ( &src == this )
|
||||||
{
|
return *this;
|
||||||
if ( m_owned )
|
|
||||||
free(m_str);
|
DecRef();
|
||||||
CopyFrom(src);
|
m_data = src.m_data;
|
||||||
}
|
IncRef();
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool extend(size_t len)
|
bool extend(size_t len)
|
||||||
{
|
{
|
||||||
wxASSERT_MSG( m_owned, _T("cannot extend non-owned buffer") );
|
wxASSERT_MSG( m_data->m_owned, _T("cannot extend non-owned buffer") );
|
||||||
|
wxASSERT_MSG( m_data->m_ref == 1, _T("can't extend shared buffer") );
|
||||||
|
|
||||||
CharType *
|
CharType *str =
|
||||||
str = (CharType *)realloc(m_str, (len + 1)*sizeof(CharType));
|
(CharType *)realloc(data(), (len + 1) * sizeof(CharType));
|
||||||
if ( !str )
|
if ( !str )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_str = str;
|
if ( m_data == &NullData )
|
||||||
|
{
|
||||||
|
m_data = new Data(str);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_data->m_str = str;
|
||||||
|
m_data->m_owned = true;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CharType *data() { return m_str; }
|
CharType *data() { return m_data->m_str; }
|
||||||
const CharType *data() const { return m_str; }
|
const CharType *data() const { return m_data->m_str; }
|
||||||
operator const CharType *() const { return m_str; }
|
operator const CharType *() const { return data(); }
|
||||||
CharType operator[](size_t n) const { return m_str[n]; }
|
CharType operator[](size_t n) const { return data()[n]; }
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CharType *DoRelease() const
|
// reference-counted data
|
||||||
|
struct Data
|
||||||
{
|
{
|
||||||
CharType *p = m_str;
|
enum Kind
|
||||||
((wxCharTypeBuffer *)this)->m_str = NULL;
|
{
|
||||||
return p;
|
Owned,
|
||||||
|
NonOwned
|
||||||
|
};
|
||||||
|
|
||||||
|
Data(CharType *str, Kind kind = Owned)
|
||||||
|
: m_str(str), m_ref(1), m_owned(kind == Owned) {}
|
||||||
|
|
||||||
|
~Data()
|
||||||
|
{
|
||||||
|
if ( m_owned )
|
||||||
|
free(m_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyFrom(const wxCharTypeBuffer& src)
|
|
||||||
{
|
|
||||||
m_owned = src.m_owned;
|
|
||||||
m_str = src.DoRelease();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
CharType *m_str;
|
CharType *m_str;
|
||||||
|
|
||||||
|
// "short" to have sizeof(Data)=8 on 32bit archs
|
||||||
|
unsigned short m_ref;
|
||||||
|
|
||||||
bool m_owned;
|
bool m_owned;
|
||||||
|
};
|
||||||
|
|
||||||
|
// placeholder for NULL string, to simplify this code
|
||||||
|
// NB: this is defined in string.cpp, not (non-existent) buffer.cpp
|
||||||
|
static Data NullData;
|
||||||
|
|
||||||
|
void IncRef()
|
||||||
|
{
|
||||||
|
if ( m_data == &NullData ) // exception, not ref-counted
|
||||||
|
return;
|
||||||
|
m_data->m_ref++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DecRef()
|
||||||
|
{
|
||||||
|
if ( m_data == &NullData ) // exception, not ref-counted
|
||||||
|
return;
|
||||||
|
if ( --m_data->m_ref == 0 )
|
||||||
|
delete m_data;
|
||||||
|
m_data = &NullData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Data *m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxCharTypeBuffer<char> )
|
WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxCharTypeBuffer<char> )
|
||||||
|
@@ -2009,3 +2009,15 @@ wxUTF8StringBufferLength::~wxUTF8StringBufferLength()
|
|||||||
wbuf.SetLength(wlen);
|
wbuf.SetLength(wlen);
|
||||||
}
|
}
|
||||||
#endif // wxUSE_UNICODE_WCHAR
|
#endif // wxUSE_UNICODE_WCHAR
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// wxCharBufferType<T>
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template<>
|
||||||
|
wxCharTypeBuffer<char>::Data
|
||||||
|
wxCharTypeBuffer<char>::NullData(NULL);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
wxCharTypeBuffer<wchar_t>::Data
|
||||||
|
wxCharTypeBuffer<wchar_t>::NullData(NULL);
|
||||||
|
Reference in New Issue
Block a user