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