]> git.saurik.com Git - wxWidgets.git/blame_incremental - include/wx/buffer.h
fix the bug in insert(end(), value) and added unit test for it
[wxWidgets.git] / include / wx / buffer.h
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: wx/buffer.h
3// Purpose: auto buffer classes: buffers which automatically free memory
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 12.04.99
7// RCS-ID: $Id$
8// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// Licence: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12#ifndef _WX_BUFFER_H
13#define _WX_BUFFER_H
14
15#include "wx/chartype.h"
16#include "wx/wxcrtbase.h"
17
18#ifndef __WXPALMOS5__
19#include <stdlib.h> // malloc() and free()
20#endif // ! __WXPALMOS5__
21
22class WXDLLIMPEXP_FWD_BASE wxCStrData;
23
24// ----------------------------------------------------------------------------
25// Special classes for (wide) character strings: they use malloc/free instead
26// of new/delete
27// ----------------------------------------------------------------------------
28
29template <typename T>
30class WXDLLIMPEXP_BASE wxCharTypeBuffer
31{
32public:
33 typedef T CharType;
34
35 wxCharTypeBuffer(const CharType *str = NULL)
36 {
37 if ( str )
38 m_data = new Data(wxStrdup(str));
39 else
40 m_data = &NullData;
41 }
42
43 wxCharTypeBuffer(size_t len)
44 {
45 m_data = new Data((CharType *)malloc((len + 1)*sizeof(CharType)));
46 m_data->m_str[len] = (CharType)0;
47 }
48
49 static const wxCharTypeBuffer CreateNonOwned(const CharType *str)
50 {
51 wxCharTypeBuffer buf;
52 if ( str )
53 buf.m_data = new Data(wx_const_cast(CharType*, str), Data::NonOwned);
54 return buf;
55 }
56
57 ~wxCharTypeBuffer()
58 {
59 DecRef();
60 }
61
62 // NB: this method is only const for backward compatibility. It used to
63 // be needed for auto_ptr-like semantics of the copy ctor, but now
64 // that ref-counting is used, it's not really needed.
65 CharType *release() const
66 {
67 if ( m_data == &NullData )
68 return NULL;
69
70 wxASSERT_MSG( m_data->m_owned, _T("can't release non-owned buffer") );
71 wxASSERT_MSG( m_data->m_ref == 1, _T("can't release shared buffer") );
72
73 CharType *p = m_data->m_str;
74
75 wxCharTypeBuffer *self = wx_const_cast(wxCharTypeBuffer*, this);
76 self->m_data->m_str = NULL;
77 self->DecRef();
78
79 return p;
80 }
81
82 void reset()
83 {
84 DecRef();
85 }
86
87 wxCharTypeBuffer(const wxCharTypeBuffer& src)
88 {
89 m_data = src.m_data;
90 IncRef();
91 }
92
93 wxCharTypeBuffer& operator=(const CharType *str)
94 {
95 DecRef();
96
97 if ( str )
98 m_data = new Data(wxStrdup(str));
99 return *this;
100 }
101
102 wxCharTypeBuffer& operator=(const wxCharTypeBuffer& src)
103 {
104 if ( &src == this )
105 return *this;
106
107 DecRef();
108 m_data = src.m_data;
109 IncRef();
110
111 return *this;
112 }
113
114 bool extend(size_t len)
115 {
116 wxASSERT_MSG( m_data->m_owned, _T("cannot extend non-owned buffer") );
117 wxASSERT_MSG( m_data->m_ref == 1, _T("can't extend shared buffer") );
118
119 CharType *str =
120 (CharType *)realloc(data(), (len + 1) * sizeof(CharType));
121 if ( !str )
122 return false;
123
124 if ( m_data == &NullData )
125 {
126 m_data = new Data(str);
127 }
128 else
129 {
130 m_data->m_str = str;
131 m_data->m_owned = true;
132 }
133
134 return true;
135 }
136
137 CharType *data() { return m_data->m_str; }
138 const CharType *data() const { return m_data->m_str; }
139 operator const CharType *() const { return data(); }
140 CharType operator[](size_t n) const { return data()[n]; }
141
142private:
143 // reference-counted data
144 struct Data
145 {
146 enum Kind
147 {
148 Owned,
149 NonOwned
150 };
151
152 Data(CharType *str, Kind kind = Owned)
153 : m_str(str), m_ref(1), m_owned(kind == Owned) {}
154
155 ~Data()
156 {
157 if ( m_owned )
158 free(m_str);
159 }
160
161 CharType *m_str;
162
163 // "short" to have sizeof(Data)=8 on 32bit archs
164 unsigned short m_ref;
165
166 bool m_owned;
167 };
168
169 // placeholder for NULL string, to simplify this code
170 // NB: this is defined in string.cpp, not (non-existent) buffer.cpp
171#ifdef __MINGW32__
172 // MinGW requires explicit WXDLLIMPEXP_DATA_BASE to avoid compilation
173 // errors
174 static WXDLLIMPEXP_DATA_BASE(Data) NullData;
175#else
176 // but Visual C++ doesn't like it
177 static Data NullData;
178#endif
179
180 void IncRef()
181 {
182 if ( m_data == &NullData ) // exception, not ref-counted
183 return;
184 m_data->m_ref++;
185 }
186
187 void DecRef()
188 {
189 if ( m_data == &NullData ) // exception, not ref-counted
190 return;
191 if ( --m_data->m_ref == 0 )
192 delete m_data;
193 m_data = &NullData;
194 }
195
196private:
197 Data *m_data;
198};
199
200WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxCharTypeBuffer<char> )
201
202class WXDLLIMPEXP_BASE wxCharBuffer : public wxCharTypeBuffer<char>
203{
204public:
205 typedef wxCharTypeBuffer<char> wxCharTypeBufferBase;
206
207 wxCharBuffer(const wxCharTypeBufferBase& buf)
208 : wxCharTypeBufferBase(buf) {}
209
210 wxCharBuffer(const CharType *str = NULL) : wxCharTypeBufferBase(str) {}
211 wxCharBuffer(size_t len) : wxCharTypeBufferBase(len) {}
212
213 wxCharBuffer(const wxCStrData& cstr);
214};
215
216#if wxUSE_WCHAR_T
217WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxCharTypeBuffer<wchar_t> )
218
219class WXDLLIMPEXP_BASE wxWCharBuffer : public wxCharTypeBuffer<wchar_t>
220{
221public:
222 typedef wxCharTypeBuffer<wchar_t> wxCharTypeBufferBase;
223
224 wxWCharBuffer(const wxCharTypeBufferBase& buf)
225 : wxCharTypeBufferBase(buf) {}
226
227 wxWCharBuffer(const CharType *str = NULL) : wxCharTypeBufferBase(str) {}
228 wxWCharBuffer(size_t len) : wxCharTypeBufferBase(len) {}
229
230 wxWCharBuffer(const wxCStrData& cstr);
231};
232#endif // wxUSE_WCHAR_T
233
234// wxCharTypeBuffer<T> implicitly convertible to T*
235template <typename T>
236class wxWritableCharTypeBuffer : public wxCharTypeBuffer<T>
237{
238public:
239 typedef typename wxCharTypeBuffer<T>::CharType CharType;
240
241 wxWritableCharTypeBuffer(const wxCharTypeBuffer<T>& src)
242 : wxCharTypeBuffer<T>(src) {}
243 // FIXME-UTF8: this won't be needed after converting mb_str()/wc_str() to
244 // always return a buffer
245 wxWritableCharTypeBuffer(const CharType *str = NULL)
246 : wxCharTypeBuffer<T>(str) {}
247
248 operator CharType*() { return this->data(); }
249};
250
251typedef wxWritableCharTypeBuffer<char> wxWritableCharBuffer;
252typedef wxWritableCharTypeBuffer<wchar_t> wxWritableWCharBuffer;
253
254
255#if wxUSE_UNICODE
256 #define wxWxCharBuffer wxWCharBuffer
257
258 #define wxMB2WXbuf wxWCharBuffer
259 #define wxWX2MBbuf wxCharBuffer
260 #if wxUSE_UNICODE_WCHAR
261 #define wxWC2WXbuf wxChar*
262 #define wxWX2WCbuf wxChar*
263 #elif wxUSE_UNICODE_UTF8
264 #define wxWC2WXbuf wxWCharBuffer
265 #define wxWX2WCbuf wxWCharBuffer
266 #endif
267#else // ANSI
268 #define wxWxCharBuffer wxCharBuffer
269
270 #define wxMB2WXbuf wxChar*
271 #define wxWX2MBbuf wxChar*
272 #define wxWC2WXbuf wxCharBuffer
273 #define wxWX2WCbuf wxWCharBuffer
274#endif // Unicode/ANSI
275
276// type of the value returned by wxString::utf8_str()
277#if wxUSE_UNICODE_UTF8
278 #define wxUTF8Buf char *
279#else
280 #define wxUTF8Buf wxCharBuffer
281#endif
282
283// ----------------------------------------------------------------------------
284// A class for holding growable data buffers (not necessarily strings)
285// ----------------------------------------------------------------------------
286
287// This class manages the actual data buffer pointer and is ref-counted.
288class wxMemoryBufferData
289{
290public:
291 // the initial size and also the size added by ResizeIfNeeded()
292 enum { DefBufSize = 1024 };
293
294 friend class wxMemoryBuffer;
295
296 // everyting is private as it can only be used by wxMemoryBuffer
297private:
298 wxMemoryBufferData(size_t size = wxMemoryBufferData::DefBufSize)
299 : m_data(size ? malloc(size) : NULL), m_size(size), m_len(0), m_ref(0)
300 {
301 }
302 ~wxMemoryBufferData() { free(m_data); }
303
304
305 void ResizeIfNeeded(size_t newSize)
306 {
307 if (newSize > m_size)
308 {
309 void *dataOld = m_data;
310 m_data = realloc(m_data, newSize + wxMemoryBufferData::DefBufSize);
311 if ( !m_data )
312 {
313 free(dataOld);
314 }
315
316 m_size = newSize + wxMemoryBufferData::DefBufSize;
317 }
318 }
319
320 void IncRef() { m_ref += 1; }
321 void DecRef()
322 {
323 m_ref -= 1;
324 if (m_ref == 0) // are there no more references?
325 delete this;
326 }
327
328
329 // the buffer containing the data
330 void *m_data;
331
332 // the size of the buffer
333 size_t m_size;
334
335 // the amount of data currently in the buffer
336 size_t m_len;
337
338 // the reference count
339 size_t m_ref;
340
341 DECLARE_NO_COPY_CLASS(wxMemoryBufferData)
342};
343
344
345class WXDLLIMPEXP_BASE wxMemoryBuffer
346{
347public:
348 // ctor and dtor
349 wxMemoryBuffer(size_t size = wxMemoryBufferData::DefBufSize)
350 {
351 m_bufdata = new wxMemoryBufferData(size);
352 m_bufdata->IncRef();
353 }
354
355 ~wxMemoryBuffer() { m_bufdata->DecRef(); }
356
357
358 // copy and assignment
359 wxMemoryBuffer(const wxMemoryBuffer& src)
360 : m_bufdata(src.m_bufdata)
361 {
362 m_bufdata->IncRef();
363 }
364
365 wxMemoryBuffer& operator=(const wxMemoryBuffer& src)
366 {
367 if (&src != this)
368 {
369 m_bufdata->DecRef();
370 m_bufdata = src.m_bufdata;
371 m_bufdata->IncRef();
372 }
373 return *this;
374 }
375
376
377 // Accessors
378 void *GetData() const { return m_bufdata->m_data; }
379 size_t GetBufSize() const { return m_bufdata->m_size; }
380 size_t GetDataLen() const { return m_bufdata->m_len; }
381
382 void SetBufSize(size_t size) { m_bufdata->ResizeIfNeeded(size); }
383 void SetDataLen(size_t len)
384 {
385 wxASSERT(len <= m_bufdata->m_size);
386 m_bufdata->m_len = len;
387 }
388
389 // Ensure the buffer is big enough and return a pointer to it
390 void *GetWriteBuf(size_t sizeNeeded)
391 {
392 m_bufdata->ResizeIfNeeded(sizeNeeded);
393 return m_bufdata->m_data;
394 }
395
396 // Update the length after the write
397 void UngetWriteBuf(size_t sizeUsed) { SetDataLen(sizeUsed); }
398
399 // Like the above, but appends to the buffer
400 void *GetAppendBuf(size_t sizeNeeded)
401 {
402 m_bufdata->ResizeIfNeeded(m_bufdata->m_len + sizeNeeded);
403 return (char*)m_bufdata->m_data + m_bufdata->m_len;
404 }
405
406 // Update the length after the append
407 void UngetAppendBuf(size_t sizeUsed)
408 {
409 SetDataLen(m_bufdata->m_len + sizeUsed);
410 }
411
412 // Other ways to append to the buffer
413 void AppendByte(char data)
414 {
415 wxCHECK_RET( m_bufdata->m_data, _T("invalid wxMemoryBuffer") );
416
417 m_bufdata->ResizeIfNeeded(m_bufdata->m_len + 1);
418 *(((char*)m_bufdata->m_data) + m_bufdata->m_len) = data;
419 m_bufdata->m_len += 1;
420 }
421
422 void AppendData(const void *data, size_t len)
423 {
424 memcpy(GetAppendBuf(len), data, len);
425 UngetAppendBuf(len);
426 }
427
428 operator const char *() const { return (const char*)GetData(); }
429
430private:
431 wxMemoryBufferData* m_bufdata;
432};
433
434// ----------------------------------------------------------------------------
435// template class for any kind of data
436// ----------------------------------------------------------------------------
437
438// TODO
439
440#endif // _WX_BUFFER_H