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"
18 #include <stdlib.h> // malloc() and free()
20 class WXDLLIMPEXP_FWD_BASE wxCStrData
;
22 // ----------------------------------------------------------------------------
23 // Special classes for (wide) character strings: they use malloc/free instead
25 // ----------------------------------------------------------------------------
27 // helpers used by wxCharTypeBuffer
31 struct UntypedBufferData
39 UntypedBufferData(void *str
, size_t len
, Kind kind
= Owned
)
40 : m_str(str
), m_length(len
), m_ref(1), m_owned(kind
== Owned
) {}
51 // "short" to have sizeof(Data)=12 on 32bit archs
57 // NB: this is defined in string.cpp and not the (non-existent) buffer.cpp
58 WXDLLIMPEXP_BASE UntypedBufferData
* GetUntypedNullData();
60 } // namespace wxPrivate
63 // Reference-counted character buffer for storing string data. The buffer
64 // is only valid for as long as the "parent" object that provided the data
65 // is valid; see wxCharTypeBuffer<T> for persistent variant.
67 class wxScopedCharTypeBuffer
72 wxScopedCharTypeBuffer()
74 m_data
= GetNullData();
77 // Creates "non-owned" buffer, i.e. 'str' is not owned by the buffer
78 // and doesn't get freed by dtor. Used e.g. to point to wxString's internal
81 const wxScopedCharTypeBuffer
CreateNonOwned(const CharType
*str
,
82 size_t len
= wxNO_LEN
)
84 if ( len
== wxNO_LEN
)
87 wxScopedCharTypeBuffer buf
;
89 buf
.m_data
= new Data(const_cast<CharType
*>(str
), len
, Data::NonOwned
);
93 // Creates "owned" buffer, i.e. takes over ownership of 'str' and frees it
94 // in dtor (if ref.count reaches 0).
96 const wxScopedCharTypeBuffer
CreateOwned(CharType
*str
,
97 size_t len
= wxNO_LEN
)
99 if ( len
== wxNO_LEN
)
102 wxScopedCharTypeBuffer buf
;
104 buf
.m_data
= new Data(str
, len
);
108 wxScopedCharTypeBuffer(const wxScopedCharTypeBuffer
& src
)
114 wxScopedCharTypeBuffer
& operator=(const wxScopedCharTypeBuffer
& src
)
126 ~wxScopedCharTypeBuffer()
131 // NB: this method is only const for backward compatibility. It used to
132 // be needed for auto_ptr-like semantics of the copy ctor, but now
133 // that ref-counting is used, it's not really needed.
134 CharType
*release() const
136 if ( m_data
== GetNullData() )
139 wxASSERT_MSG( m_data
->m_owned
, wxT("can't release non-owned buffer") );
140 wxASSERT_MSG( m_data
->m_ref
== 1, wxT("can't release shared buffer") );
142 CharType
* const p
= m_data
->Get();
144 wxScopedCharTypeBuffer
*self
= const_cast<wxScopedCharTypeBuffer
*>(this);
145 self
->m_data
->Set(NULL
, 0);
156 CharType
*data() { return m_data
->Get(); }
157 const CharType
*data() const { return m_data
->Get(); }
158 operator const CharType
*() const { return data(); }
159 CharType
operator[](size_t n
) const { return data()[n
]; }
161 size_t length() const { return m_data
->m_length
; }
164 // reference-counted data
165 struct Data
: public wxPrivate::UntypedBufferData
167 Data(CharType
*str
, size_t len
, Kind kind
= Owned
)
168 : wxPrivate::UntypedBufferData(str
, len
, kind
)
172 CharType
*Get() const { return static_cast<CharType
*>(m_str
); }
173 void Set(CharType
*str
, size_t len
)
180 // placeholder for NULL string, to simplify this code
181 static Data
*GetNullData()
183 return static_cast<Data
*>(wxPrivate::GetUntypedNullData());
188 if ( m_data
== GetNullData() ) // exception, not ref-counted
195 if ( m_data
== GetNullData() ) // exception, not ref-counted
197 if ( --m_data
->m_ref
== 0 )
199 m_data
= GetNullData();
202 // sets this object to a be copy of 'other'; if 'src' is non-owned,
203 // a deep copy is made and 'this' will contain new instance of the data
204 void MakeOwnedCopyOf(const wxScopedCharTypeBuffer
& src
)
208 if ( src
.m_data
== this->GetNullData() )
210 this->m_data
= this->GetNullData();
212 else if ( src
.m_data
->m_owned
)
214 this->m_data
= src
.m_data
;
219 // if the scoped buffer had non-owned data, we have to make
220 // a copy here, because src.m_data->m_str is valid only for as long
222 this->m_data
= new Data
224 StrCopy(src
.data(), src
.length()),
230 static CharType
*StrCopy(const CharType
*src
, size_t len
)
232 CharType
*dst
= (CharType
*)malloc(sizeof(CharType
) * (len
+ 1));
233 memcpy(dst
, src
, sizeof(CharType
) * (len
+ 1));
241 typedef wxScopedCharTypeBuffer
<char> wxScopedCharBuffer
;
242 typedef wxScopedCharTypeBuffer
<wchar_t> wxScopedWCharBuffer
;
245 // this buffer class always stores data in "owned" (persistent) manner
246 template <typename T
>
247 class wxCharTypeBuffer
: public wxScopedCharTypeBuffer
<T
>
250 typedef typename wxScopedCharTypeBuffer
<T
>::Data Data
;
255 wxCharTypeBuffer(const CharType
*str
= NULL
, size_t len
= wxNO_LEN
)
259 if ( len
== wxNO_LEN
)
261 this->m_data
= new Data(this->StrCopy(str
, len
), len
);
265 this->m_data
= this->GetNullData();
269 wxCharTypeBuffer(size_t len
)
272 new Data((CharType
*)malloc((len
+ 1)*sizeof(CharType
)), len
);
273 this->m_data
->Get()[len
] = (CharType
)0;
276 wxCharTypeBuffer(const wxCharTypeBuffer
& src
)
277 : wxScopedCharTypeBuffer
<T
>(src
) {}
279 wxCharTypeBuffer
& operator=(const CharType
*str
)
284 this->m_data
= new Data(wxStrdup(str
), wxStrlen(str
));
288 wxCharTypeBuffer
& operator=(const wxCharTypeBuffer
& src
)
290 wxScopedCharTypeBuffer
<T
>::operator=(src
);
294 wxCharTypeBuffer(const wxScopedCharTypeBuffer
<T
>& src
)
296 this->MakeOwnedCopyOf(src
);
299 wxCharTypeBuffer
& operator=(const wxScopedCharTypeBuffer
<T
>& src
)
301 MakeOwnedCopyOf(src
);
305 bool extend(size_t len
)
307 wxASSERT_MSG( this->m_data
->m_owned
, "cannot extend non-owned buffer" );
308 wxASSERT_MSG( this->m_data
->m_ref
== 1, "can't extend shared buffer" );
311 (CharType
*)realloc(this->data(), (len
+ 1) * sizeof(CharType
));
315 // For consistency with the ctor taking just the length, NUL-terminate
317 str
[len
] = (CharType
)0;
319 if ( this->m_data
== this->GetNullData() )
321 this->m_data
= new Data(str
, len
);
325 this->m_data
->Set(str
, len
);
326 this->m_data
->m_owned
= true;
332 void shrink(size_t len
)
334 wxASSERT_MSG( this->m_data
->m_owned
, "cannot shrink non-owned buffer" );
335 wxASSERT_MSG( this->m_data
->m_ref
== 1, "can't shrink shared buffer" );
337 wxASSERT( len
<= this->length() );
339 this->m_data
->m_length
= len
;
340 this->data()[len
] = 0;
344 WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxScopedCharTypeBuffer
<char> )
345 WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxCharTypeBuffer
<char> )
347 class wxCharBuffer
: public wxCharTypeBuffer
<char>
350 typedef wxCharTypeBuffer
<char> wxCharTypeBufferBase
;
351 typedef wxScopedCharTypeBuffer
<char> wxScopedCharTypeBufferBase
;
353 wxCharBuffer(const wxCharTypeBufferBase
& buf
)
354 : wxCharTypeBufferBase(buf
) {}
355 wxCharBuffer(const wxScopedCharTypeBufferBase
& buf
)
356 : wxCharTypeBufferBase(buf
) {}
358 wxCharBuffer(const CharType
*str
= NULL
) : wxCharTypeBufferBase(str
) {}
359 wxCharBuffer(size_t len
) : wxCharTypeBufferBase(len
) {}
361 wxCharBuffer(const wxCStrData
& cstr
);
364 WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxScopedCharTypeBuffer
<wchar_t> )
365 WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxCharTypeBuffer
<wchar_t> )
367 class wxWCharBuffer
: public wxCharTypeBuffer
<wchar_t>
370 typedef wxCharTypeBuffer
<wchar_t> wxCharTypeBufferBase
;
371 typedef wxScopedCharTypeBuffer
<wchar_t> wxScopedCharTypeBufferBase
;
373 wxWCharBuffer(const wxCharTypeBufferBase
& buf
)
374 : wxCharTypeBufferBase(buf
) {}
375 wxWCharBuffer(const wxScopedCharTypeBufferBase
& buf
)
376 : wxCharTypeBufferBase(buf
) {}
378 wxWCharBuffer(const CharType
*str
= NULL
) : wxCharTypeBufferBase(str
) {}
379 wxWCharBuffer(size_t len
) : wxCharTypeBufferBase(len
) {}
381 wxWCharBuffer(const wxCStrData
& cstr
);
384 // wxCharTypeBuffer<T> implicitly convertible to T*
385 template <typename T
>
386 class wxWritableCharTypeBuffer
: public wxCharTypeBuffer
<T
>
389 typedef typename wxScopedCharTypeBuffer
<T
>::CharType CharType
;
391 wxWritableCharTypeBuffer(const wxScopedCharTypeBuffer
<T
>& src
)
392 : wxCharTypeBuffer
<T
>(src
) {}
393 // FIXME-UTF8: this won't be needed after converting mb_str()/wc_str() to
394 // always return a buffer
395 // + we should derive this class from wxScopedCharTypeBuffer
397 wxWritableCharTypeBuffer(const CharType
*str
= NULL
)
398 : wxCharTypeBuffer
<T
>(str
) {}
400 operator CharType
*() { return this->data(); }
403 typedef wxWritableCharTypeBuffer
<char> wxWritableCharBuffer
;
404 typedef wxWritableCharTypeBuffer
<wchar_t> wxWritableWCharBuffer
;
408 #define wxWxCharBuffer wxWCharBuffer
410 #define wxMB2WXbuf wxWCharBuffer
411 #define wxWX2MBbuf wxCharBuffer
412 #if wxUSE_UNICODE_WCHAR
413 #define wxWC2WXbuf wxChar*
414 #define wxWX2WCbuf wxChar*
415 #elif wxUSE_UNICODE_UTF8
416 #define wxWC2WXbuf wxWCharBuffer
417 #define wxWX2WCbuf wxWCharBuffer
420 #define wxWxCharBuffer wxCharBuffer
422 #define wxMB2WXbuf wxChar*
423 #define wxWX2MBbuf wxChar*
424 #define wxWC2WXbuf wxCharBuffer
425 #define wxWX2WCbuf wxWCharBuffer
426 #endif // Unicode/ANSI
428 // ----------------------------------------------------------------------------
429 // A class for holding growable data buffers (not necessarily strings)
430 // ----------------------------------------------------------------------------
432 // This class manages the actual data buffer pointer and is ref-counted.
433 class wxMemoryBufferData
436 // the initial size and also the size added by ResizeIfNeeded()
437 enum { DefBufSize
= 1024 };
439 friend class wxMemoryBuffer
;
441 // everyting is private as it can only be used by wxMemoryBuffer
443 wxMemoryBufferData(size_t size
= wxMemoryBufferData::DefBufSize
)
444 : m_data(size
? malloc(size
) : NULL
), m_size(size
), m_len(0), m_ref(0)
447 ~wxMemoryBufferData() { free(m_data
); }
450 void ResizeIfNeeded(size_t newSize
)
452 if (newSize
> m_size
)
454 void *dataOld
= m_data
;
455 m_data
= realloc(m_data
, newSize
+ wxMemoryBufferData::DefBufSize
);
461 m_size
= newSize
+ wxMemoryBufferData::DefBufSize
;
465 void IncRef() { m_ref
+= 1; }
469 if (m_ref
== 0) // are there no more references?
475 if ( m_data
== NULL
)
478 wxASSERT_MSG( m_ref
== 1, "can't release shared buffer" );
489 // the buffer containing the data
492 // the size of the buffer
495 // the amount of data currently in the buffer
498 // the reference count
501 wxDECLARE_NO_COPY_CLASS(wxMemoryBufferData
);
509 wxMemoryBuffer(size_t size
= wxMemoryBufferData::DefBufSize
)
511 m_bufdata
= new wxMemoryBufferData(size
);
515 ~wxMemoryBuffer() { m_bufdata
->DecRef(); }
518 // copy and assignment
519 wxMemoryBuffer(const wxMemoryBuffer
& src
)
520 : m_bufdata(src
.m_bufdata
)
525 wxMemoryBuffer
& operator=(const wxMemoryBuffer
& src
)
530 m_bufdata
= src
.m_bufdata
;
538 void *GetData() const { return m_bufdata
->m_data
; }
539 size_t GetBufSize() const { return m_bufdata
->m_size
; }
540 size_t GetDataLen() const { return m_bufdata
->m_len
; }
542 bool IsEmpty() const { return GetDataLen() == 0; }
544 void SetBufSize(size_t size
) { m_bufdata
->ResizeIfNeeded(size
); }
545 void SetDataLen(size_t len
)
547 wxASSERT(len
<= m_bufdata
->m_size
);
548 m_bufdata
->m_len
= len
;
551 void Clear() { SetDataLen(0); }
553 // Ensure the buffer is big enough and return a pointer to it
554 void *GetWriteBuf(size_t sizeNeeded
)
556 m_bufdata
->ResizeIfNeeded(sizeNeeded
);
557 return m_bufdata
->m_data
;
560 // Update the length after the write
561 void UngetWriteBuf(size_t sizeUsed
) { SetDataLen(sizeUsed
); }
563 // Like the above, but appends to the buffer
564 void *GetAppendBuf(size_t sizeNeeded
)
566 m_bufdata
->ResizeIfNeeded(m_bufdata
->m_len
+ sizeNeeded
);
567 return (char*)m_bufdata
->m_data
+ m_bufdata
->m_len
;
570 // Update the length after the append
571 void UngetAppendBuf(size_t sizeUsed
)
573 SetDataLen(m_bufdata
->m_len
+ sizeUsed
);
576 // Other ways to append to the buffer
577 void AppendByte(char data
)
579 wxCHECK_RET( m_bufdata
->m_data
, wxT("invalid wxMemoryBuffer") );
581 m_bufdata
->ResizeIfNeeded(m_bufdata
->m_len
+ 1);
582 *(((char*)m_bufdata
->m_data
) + m_bufdata
->m_len
) = data
;
583 m_bufdata
->m_len
+= 1;
586 void AppendData(const void *data
, size_t len
)
588 memcpy(GetAppendBuf(len
), data
, len
);
592 operator const char *() const { return (const char*)GetData(); }
594 // gives up ownership of data, returns the pointer; after this call,
595 // data isn't freed by the buffer and its content is resent to empty
598 return m_bufdata
->release();
602 wxMemoryBufferData
* m_bufdata
;
605 // ----------------------------------------------------------------------------
606 // template class for any kind of data
607 // ----------------------------------------------------------------------------
611 #endif // _WX_BUFFER_H