1 ///////////////////////////////////////////////////////////////////////////////
3 // Purpose: auto buffer classes: buffers which automatically free memory
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
15 #include "wx/chartype.h"
16 #include "wx/wxcrtbase.h"
19 #include <stdlib.h> // malloc() and free()
20 #endif // ! __WXPALMOS5__
22 class WXDLLIMPEXP_FWD_BASE wxCStrData
;
24 // ----------------------------------------------------------------------------
25 // Special classes for (wide) character strings: they use malloc/free instead
27 // ----------------------------------------------------------------------------
29 // helpers used by wxCharTypeBuffer
33 struct UntypedBufferData
41 UntypedBufferData(void *str
, Kind kind
= Owned
)
42 : m_str(str
), m_ref(1), m_owned(kind
== Owned
) {}
52 // "short" to have sizeof(Data)=8 on 32bit archs
58 // this has to be defined inside the DLL (and not e.g. as a static variable
59 // inside an inline function) as otherwise MSVC gives link errors when the
60 // functions are effectively inlined (i.e. in non-debug build)
62 // NB: this is defined in string.cpp and not the (non-existent) buffer.cpp
63 extern WXDLLIMPEXP_DATA_BASE(UntypedBufferData
* const) untypedNullDataPtr
;
65 } // namespace wxPrivate
68 // Reference-counted character buffer for storing string data. The buffer
69 // is only valid for as long as the "parent" object that provided the data
70 // is valid; see wxCharTypeBuffer<T> for persistent variant.
72 class wxScopedCharTypeBuffer
77 wxScopedCharTypeBuffer()
79 m_data
= GetNullData();
82 // Creates "non-owned" buffer, i.e. 'str' is not owned by the buffer
83 // and doesn't get freed by dtor. Used e.g. to point to wxString's internal
85 static const wxScopedCharTypeBuffer
CreateNonOwned(const CharType
*str
)
87 wxScopedCharTypeBuffer buf
;
89 buf
.m_data
= new Data(const_cast<CharType
*>(str
), Data::NonOwned
);
93 // Creates "owned" buffer, i.e. takes over ownership of 'str' and frees it
94 // in dtor (if ref.count reaches 0).
95 static const wxScopedCharTypeBuffer
CreateOwned(const CharType
*str
)
97 wxScopedCharTypeBuffer buf
;
99 buf
.m_data
= new Data(wxStrdup(str
));
103 wxScopedCharTypeBuffer(const wxScopedCharTypeBuffer
& src
)
109 wxScopedCharTypeBuffer
& operator=(const wxScopedCharTypeBuffer
& src
)
121 ~wxScopedCharTypeBuffer()
126 // NB: this method is only const for backward compatibility. It used to
127 // be needed for auto_ptr-like semantics of the copy ctor, but now
128 // that ref-counting is used, it's not really needed.
129 CharType
*release() const
131 if ( m_data
== GetNullData() )
134 wxASSERT_MSG( m_data
->m_owned
, _T("can't release non-owned buffer") );
135 wxASSERT_MSG( m_data
->m_ref
== 1, _T("can't release shared buffer") );
137 CharType
* const p
= m_data
->Get();
139 wxScopedCharTypeBuffer
*self
= const_cast<wxScopedCharTypeBuffer
*>(this);
140 self
->m_data
->Set(NULL
);
151 CharType
*data() { return m_data
->Get(); }
152 const CharType
*data() const { return m_data
->Get(); }
153 operator const CharType
*() const { return data(); }
154 CharType
operator[](size_t n
) const { return data()[n
]; }
157 // reference-counted data
158 struct Data
: public wxPrivate::UntypedBufferData
160 Data(CharType
*str
, Kind kind
= Owned
)
161 : wxPrivate::UntypedBufferData(str
, kind
)
165 CharType
*Get() const { return static_cast<CharType
*>(m_str
); }
166 void Set(CharType
*str
) { m_str
= str
; }
169 // placeholder for NULL string, to simplify this code
170 static Data
*GetNullData()
172 return static_cast<Data
*>(wxPrivate::untypedNullDataPtr
);
177 if ( m_data
== GetNullData() ) // exception, not ref-counted
184 if ( m_data
== GetNullData() ) // exception, not ref-counted
186 if ( --m_data
->m_ref
== 0 )
188 m_data
= GetNullData();
191 // sets this object to a be copy of 'other'; if 'src' is non-owned,
192 // a deep copy is made and 'this' will contain new instance of the data
193 void MakeOwnedCopyOf(const wxScopedCharTypeBuffer
& src
)
197 if ( src
.m_data
== this->GetNullData() )
199 this->m_data
= this->GetNullData();
201 else if ( src
.m_data
->m_owned
)
203 this->m_data
= src
.m_data
;
208 // if the scoped buffer had non-owned data, we have to make
209 // a copy here, because src.m_data->m_str is valid only for as long
211 this->m_data
= new Data(wxStrdup(src
.m_data
->Get()));
219 typedef wxScopedCharTypeBuffer
<char> wxScopedCharBuffer
;
220 typedef wxScopedCharTypeBuffer
<wchar_t> wxScopedWCharBuffer
;
223 // this buffer class always stores data in "owned" (persistent) manner
224 template <typename T
>
225 class wxCharTypeBuffer
: public wxScopedCharTypeBuffer
<T
>
228 typedef typename wxScopedCharTypeBuffer
<T
>::Data Data
;
233 wxCharTypeBuffer(const CharType
*str
= NULL
)
236 this->m_data
= new Data(wxStrdup(str
));
238 this->m_data
= this->GetNullData();
241 wxCharTypeBuffer(size_t len
)
243 this->m_data
= new Data((CharType
*)malloc((len
+ 1)*sizeof(CharType
)));
244 this->m_data
->Get()[len
] = (CharType
)0;
247 wxCharTypeBuffer(const wxCharTypeBuffer
& src
)
248 : wxScopedCharTypeBuffer
<T
>(src
) {}
250 wxCharTypeBuffer
& operator=(const CharType
*str
)
255 this->m_data
= new Data(wxStrdup(str
));
259 wxCharTypeBuffer
& operator=(const wxCharTypeBuffer
& src
)
261 wxScopedCharTypeBuffer
<T
>::operator=(src
);
265 wxCharTypeBuffer(const wxScopedCharTypeBuffer
<T
>& src
)
267 MakeOwnedCopyOf(src
);
270 wxCharTypeBuffer
& operator=(const wxScopedCharTypeBuffer
<T
>& src
)
272 MakeOwnedCopyOf(src
);
276 bool extend(size_t len
)
278 wxASSERT_MSG( this->m_data
->m_owned
, "cannot extend non-owned buffer" );
279 wxASSERT_MSG( this->m_data
->m_ref
== 1, "can't extend shared buffer" );
282 (CharType
*)realloc(this->data(), (len
+ 1) * sizeof(CharType
));
286 if ( this->m_data
== this->GetNullData() )
288 this->m_data
= new Data(str
);
292 this->m_data
->Set(str
);
293 this->m_data
->m_owned
= true;
300 WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxCharTypeBuffer
<char> )
302 class wxCharBuffer
: public wxCharTypeBuffer
<char>
305 typedef wxCharTypeBuffer
<char> wxCharTypeBufferBase
;
306 typedef wxScopedCharTypeBuffer
<char> wxScopedCharTypeBufferBase
;
308 wxCharBuffer(const wxCharTypeBufferBase
& buf
)
309 : wxCharTypeBufferBase(buf
) {}
310 wxCharBuffer(const wxScopedCharTypeBufferBase
& buf
)
311 : wxCharTypeBufferBase(buf
) {}
313 wxCharBuffer(const CharType
*str
= NULL
) : wxCharTypeBufferBase(str
) {}
314 wxCharBuffer(size_t len
) : wxCharTypeBufferBase(len
) {}
316 wxCharBuffer(const wxCStrData
& cstr
);
320 WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxCharTypeBuffer
<wchar_t> )
322 class wxWCharBuffer
: public wxCharTypeBuffer
<wchar_t>
325 typedef wxCharTypeBuffer
<wchar_t> wxCharTypeBufferBase
;
326 typedef wxScopedCharTypeBuffer
<wchar_t> wxScopedCharTypeBufferBase
;
328 wxWCharBuffer(const wxCharTypeBufferBase
& buf
)
329 : wxCharTypeBufferBase(buf
) {}
330 wxWCharBuffer(const wxScopedCharTypeBufferBase
& buf
)
331 : wxCharTypeBufferBase(buf
) {}
333 wxWCharBuffer(const CharType
*str
= NULL
) : wxCharTypeBufferBase(str
) {}
334 wxWCharBuffer(size_t len
) : wxCharTypeBufferBase(len
) {}
336 wxWCharBuffer(const wxCStrData
& cstr
);
338 #endif // wxUSE_WCHAR_T
340 // wxCharTypeBuffer<T> implicitly convertible to T*
341 template <typename T
>
342 class wxWritableCharTypeBuffer
: public wxCharTypeBuffer
<T
>
345 typedef typename wxScopedCharTypeBuffer
<T
>::CharType CharType
;
347 wxWritableCharTypeBuffer(const wxScopedCharTypeBuffer
<T
>& src
)
348 : wxCharTypeBuffer
<T
>(src
) {}
349 // FIXME-UTF8: this won't be needed after converting mb_str()/wc_str() to
350 // always return a buffer
351 // + we should derive this class from wxScopedCharTypeBuffer
353 wxWritableCharTypeBuffer(const CharType
*str
= NULL
)
354 : wxCharTypeBuffer
<T
>(str
) {}
356 operator CharType
*() { return this->data(); }
359 typedef wxWritableCharTypeBuffer
<char> wxWritableCharBuffer
;
360 typedef wxWritableCharTypeBuffer
<wchar_t> wxWritableWCharBuffer
;
364 #define wxWxCharBuffer wxWCharBuffer
366 #define wxMB2WXbuf wxWCharBuffer
367 #define wxWX2MBbuf wxCharBuffer
368 #if wxUSE_UNICODE_WCHAR
369 #define wxWC2WXbuf wxChar*
370 #define wxWX2WCbuf wxChar*
371 #elif wxUSE_UNICODE_UTF8
372 #define wxWC2WXbuf wxWCharBuffer
373 #define wxWX2WCbuf wxWCharBuffer
376 #define wxWxCharBuffer wxCharBuffer
378 #define wxMB2WXbuf wxChar*
379 #define wxWX2MBbuf wxChar*
380 #define wxWC2WXbuf wxCharBuffer
381 #define wxWX2WCbuf wxWCharBuffer
382 #endif // Unicode/ANSI
384 // type of the value returned by wxString::utf8_str()
385 #if wxUSE_UNICODE_UTF8
386 #define wxUTF8Buf char *
388 #define wxUTF8Buf wxCharBuffer
391 // ----------------------------------------------------------------------------
392 // A class for holding growable data buffers (not necessarily strings)
393 // ----------------------------------------------------------------------------
395 // This class manages the actual data buffer pointer and is ref-counted.
396 class wxMemoryBufferData
399 // the initial size and also the size added by ResizeIfNeeded()
400 enum { DefBufSize
= 1024 };
402 friend class wxMemoryBuffer
;
404 // everyting is private as it can only be used by wxMemoryBuffer
406 wxMemoryBufferData(size_t size
= wxMemoryBufferData::DefBufSize
)
407 : m_data(size
? malloc(size
) : NULL
), m_size(size
), m_len(0), m_ref(0)
410 ~wxMemoryBufferData() { free(m_data
); }
413 void ResizeIfNeeded(size_t newSize
)
415 if (newSize
> m_size
)
417 void *dataOld
= m_data
;
418 m_data
= realloc(m_data
, newSize
+ wxMemoryBufferData::DefBufSize
);
424 m_size
= newSize
+ wxMemoryBufferData::DefBufSize
;
428 void IncRef() { m_ref
+= 1; }
432 if (m_ref
== 0) // are there no more references?
437 // the buffer containing the data
440 // the size of the buffer
443 // the amount of data currently in the buffer
446 // the reference count
449 wxDECLARE_NO_COPY_CLASS(wxMemoryBufferData
);
457 wxMemoryBuffer(size_t size
= wxMemoryBufferData::DefBufSize
)
459 m_bufdata
= new wxMemoryBufferData(size
);
463 ~wxMemoryBuffer() { m_bufdata
->DecRef(); }
466 // copy and assignment
467 wxMemoryBuffer(const wxMemoryBuffer
& src
)
468 : m_bufdata(src
.m_bufdata
)
473 wxMemoryBuffer
& operator=(const wxMemoryBuffer
& src
)
478 m_bufdata
= src
.m_bufdata
;
486 void *GetData() const { return m_bufdata
->m_data
; }
487 size_t GetBufSize() const { return m_bufdata
->m_size
; }
488 size_t GetDataLen() const { return m_bufdata
->m_len
; }
490 void SetBufSize(size_t size
) { m_bufdata
->ResizeIfNeeded(size
); }
491 void SetDataLen(size_t len
)
493 wxASSERT(len
<= m_bufdata
->m_size
);
494 m_bufdata
->m_len
= len
;
497 // Ensure the buffer is big enough and return a pointer to it
498 void *GetWriteBuf(size_t sizeNeeded
)
500 m_bufdata
->ResizeIfNeeded(sizeNeeded
);
501 return m_bufdata
->m_data
;
504 // Update the length after the write
505 void UngetWriteBuf(size_t sizeUsed
) { SetDataLen(sizeUsed
); }
507 // Like the above, but appends to the buffer
508 void *GetAppendBuf(size_t sizeNeeded
)
510 m_bufdata
->ResizeIfNeeded(m_bufdata
->m_len
+ sizeNeeded
);
511 return (char*)m_bufdata
->m_data
+ m_bufdata
->m_len
;
514 // Update the length after the append
515 void UngetAppendBuf(size_t sizeUsed
)
517 SetDataLen(m_bufdata
->m_len
+ sizeUsed
);
520 // Other ways to append to the buffer
521 void AppendByte(char data
)
523 wxCHECK_RET( m_bufdata
->m_data
, _T("invalid wxMemoryBuffer") );
525 m_bufdata
->ResizeIfNeeded(m_bufdata
->m_len
+ 1);
526 *(((char*)m_bufdata
->m_data
) + m_bufdata
->m_len
) = data
;
527 m_bufdata
->m_len
+= 1;
530 void AppendData(const void *data
, size_t len
)
532 memcpy(GetAppendBuf(len
), data
, len
);
536 operator const char *() const { return (const char*)GetData(); }
539 wxMemoryBufferData
* m_bufdata
;
542 // ----------------------------------------------------------------------------
543 // template class for any kind of data
544 // ----------------------------------------------------------------------------
548 #endif // _WX_BUFFER_H