]> git.saurik.com Git - wxWidgets.git/blob - include/wx/buffer.h
fix linking problems due to MSVC implicitly considering template classes specializati...
[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 template <typename T>
30 class wxCharTypeBuffer
31 {
32 public:
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 = GetNullData();
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 == GetNullData() )
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 == GetNullData() )
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
142 private:
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 static Data *GetNullData()
171 {
172 static Data s_nullData(NULL);
173
174 return &s_nullData;
175 }
176
177 void IncRef()
178 {
179 if ( m_data == GetNullData() ) // exception, not ref-counted
180 return;
181 m_data->m_ref++;
182 }
183
184 void DecRef()
185 {
186 if ( m_data == GetNullData() ) // exception, not ref-counted
187 return;
188 if ( --m_data->m_ref == 0 )
189 delete m_data;
190 m_data = GetNullData();
191 }
192
193 private:
194 Data *m_data;
195 };
196
197 WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxCharTypeBuffer<char> )
198
199 class wxCharBuffer : public wxCharTypeBuffer<char>
200 {
201 public:
202 typedef wxCharTypeBuffer<char> wxCharTypeBufferBase;
203
204 wxCharBuffer(const wxCharTypeBufferBase& buf)
205 : wxCharTypeBufferBase(buf) {}
206
207 wxCharBuffer(const CharType *str = NULL) : wxCharTypeBufferBase(str) {}
208 wxCharBuffer(size_t len) : wxCharTypeBufferBase(len) {}
209
210 wxCharBuffer(const wxCStrData& cstr);
211 };
212
213 #if wxUSE_WCHAR_T
214 WXDLLIMPEXP_TEMPLATE_INSTANCE_BASE( wxCharTypeBuffer<wchar_t> )
215
216 class wxWCharBuffer : public wxCharTypeBuffer<wchar_t>
217 {
218 public:
219 typedef wxCharTypeBuffer<wchar_t> wxCharTypeBufferBase;
220
221 wxWCharBuffer(const wxCharTypeBufferBase& buf)
222 : wxCharTypeBufferBase(buf) {}
223
224 wxWCharBuffer(const CharType *str = NULL) : wxCharTypeBufferBase(str) {}
225 wxWCharBuffer(size_t len) : wxCharTypeBufferBase(len) {}
226
227 wxWCharBuffer(const wxCStrData& cstr);
228 };
229 #endif // wxUSE_WCHAR_T
230
231 // wxCharTypeBuffer<T> implicitly convertible to T*
232 template <typename T>
233 class wxWritableCharTypeBuffer : public wxCharTypeBuffer<T>
234 {
235 public:
236 typedef typename wxCharTypeBuffer<T>::CharType CharType;
237
238 wxWritableCharTypeBuffer(const wxCharTypeBuffer<T>& src)
239 : wxCharTypeBuffer<T>(src) {}
240 // FIXME-UTF8: this won't be needed after converting mb_str()/wc_str() to
241 // always return a buffer
242 wxWritableCharTypeBuffer(const CharType *str = NULL)
243 : wxCharTypeBuffer<T>(str) {}
244
245 operator CharType*() { return this->data(); }
246 };
247
248 typedef wxWritableCharTypeBuffer<char> wxWritableCharBuffer;
249 typedef wxWritableCharTypeBuffer<wchar_t> wxWritableWCharBuffer;
250
251
252 #if wxUSE_UNICODE
253 #define wxWxCharBuffer wxWCharBuffer
254
255 #define wxMB2WXbuf wxWCharBuffer
256 #define wxWX2MBbuf wxCharBuffer
257 #if wxUSE_UNICODE_WCHAR
258 #define wxWC2WXbuf wxChar*
259 #define wxWX2WCbuf wxChar*
260 #elif wxUSE_UNICODE_UTF8
261 #define wxWC2WXbuf wxWCharBuffer
262 #define wxWX2WCbuf wxWCharBuffer
263 #endif
264 #else // ANSI
265 #define wxWxCharBuffer wxCharBuffer
266
267 #define wxMB2WXbuf wxChar*
268 #define wxWX2MBbuf wxChar*
269 #define wxWC2WXbuf wxCharBuffer
270 #define wxWX2WCbuf wxWCharBuffer
271 #endif // Unicode/ANSI
272
273 // type of the value returned by wxString::utf8_str()
274 #if wxUSE_UNICODE_UTF8
275 #define wxUTF8Buf char *
276 #else
277 #define wxUTF8Buf wxCharBuffer
278 #endif
279
280 // ----------------------------------------------------------------------------
281 // A class for holding growable data buffers (not necessarily strings)
282 // ----------------------------------------------------------------------------
283
284 // This class manages the actual data buffer pointer and is ref-counted.
285 class wxMemoryBufferData
286 {
287 public:
288 // the initial size and also the size added by ResizeIfNeeded()
289 enum { DefBufSize = 1024 };
290
291 friend class wxMemoryBuffer;
292
293 // everyting is private as it can only be used by wxMemoryBuffer
294 private:
295 wxMemoryBufferData(size_t size = wxMemoryBufferData::DefBufSize)
296 : m_data(size ? malloc(size) : NULL), m_size(size), m_len(0), m_ref(0)
297 {
298 }
299 ~wxMemoryBufferData() { free(m_data); }
300
301
302 void ResizeIfNeeded(size_t newSize)
303 {
304 if (newSize > m_size)
305 {
306 void *dataOld = m_data;
307 m_data = realloc(m_data, newSize + wxMemoryBufferData::DefBufSize);
308 if ( !m_data )
309 {
310 free(dataOld);
311 }
312
313 m_size = newSize + wxMemoryBufferData::DefBufSize;
314 }
315 }
316
317 void IncRef() { m_ref += 1; }
318 void DecRef()
319 {
320 m_ref -= 1;
321 if (m_ref == 0) // are there no more references?
322 delete this;
323 }
324
325
326 // the buffer containing the data
327 void *m_data;
328
329 // the size of the buffer
330 size_t m_size;
331
332 // the amount of data currently in the buffer
333 size_t m_len;
334
335 // the reference count
336 size_t m_ref;
337
338 DECLARE_NO_COPY_CLASS(wxMemoryBufferData)
339 };
340
341
342 class wxMemoryBuffer
343 {
344 public:
345 // ctor and dtor
346 wxMemoryBuffer(size_t size = wxMemoryBufferData::DefBufSize)
347 {
348 m_bufdata = new wxMemoryBufferData(size);
349 m_bufdata->IncRef();
350 }
351
352 ~wxMemoryBuffer() { m_bufdata->DecRef(); }
353
354
355 // copy and assignment
356 wxMemoryBuffer(const wxMemoryBuffer& src)
357 : m_bufdata(src.m_bufdata)
358 {
359 m_bufdata->IncRef();
360 }
361
362 wxMemoryBuffer& operator=(const wxMemoryBuffer& src)
363 {
364 if (&src != this)
365 {
366 m_bufdata->DecRef();
367 m_bufdata = src.m_bufdata;
368 m_bufdata->IncRef();
369 }
370 return *this;
371 }
372
373
374 // Accessors
375 void *GetData() const { return m_bufdata->m_data; }
376 size_t GetBufSize() const { return m_bufdata->m_size; }
377 size_t GetDataLen() const { return m_bufdata->m_len; }
378
379 void SetBufSize(size_t size) { m_bufdata->ResizeIfNeeded(size); }
380 void SetDataLen(size_t len)
381 {
382 wxASSERT(len <= m_bufdata->m_size);
383 m_bufdata->m_len = len;
384 }
385
386 // Ensure the buffer is big enough and return a pointer to it
387 void *GetWriteBuf(size_t sizeNeeded)
388 {
389 m_bufdata->ResizeIfNeeded(sizeNeeded);
390 return m_bufdata->m_data;
391 }
392
393 // Update the length after the write
394 void UngetWriteBuf(size_t sizeUsed) { SetDataLen(sizeUsed); }
395
396 // Like the above, but appends to the buffer
397 void *GetAppendBuf(size_t sizeNeeded)
398 {
399 m_bufdata->ResizeIfNeeded(m_bufdata->m_len + sizeNeeded);
400 return (char*)m_bufdata->m_data + m_bufdata->m_len;
401 }
402
403 // Update the length after the append
404 void UngetAppendBuf(size_t sizeUsed)
405 {
406 SetDataLen(m_bufdata->m_len + sizeUsed);
407 }
408
409 // Other ways to append to the buffer
410 void AppendByte(char data)
411 {
412 wxCHECK_RET( m_bufdata->m_data, _T("invalid wxMemoryBuffer") );
413
414 m_bufdata->ResizeIfNeeded(m_bufdata->m_len + 1);
415 *(((char*)m_bufdata->m_data) + m_bufdata->m_len) = data;
416 m_bufdata->m_len += 1;
417 }
418
419 void AppendData(const void *data, size_t len)
420 {
421 memcpy(GetAppendBuf(len), data, len);
422 UngetAppendBuf(len);
423 }
424
425 operator const char *() const { return (const char*)GetData(); }
426
427 private:
428 wxMemoryBufferData* m_bufdata;
429 };
430
431 // ----------------------------------------------------------------------------
432 // template class for any kind of data
433 // ----------------------------------------------------------------------------
434
435 // TODO
436
437 #endif // _WX_BUFFER_H