/[pcsx2_0.9.7]/trunk/common/include/Utilities/SafeArray.h
ViewVC logotype

Contents of /trunk/common/include/Utilities/SafeArray.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (9 years, 11 months ago) by william
File MIME type: text/plain
File size: 13949 byte(s)
committing r3113 initial commit again...
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #pragma once
17
18 #include "MemcpyFast.h"
19
20 extern void* __fastcall pcsx2_aligned_malloc(size_t size, size_t align);
21 extern void* __fastcall pcsx2_aligned_realloc(void* handle, size_t size, size_t align);
22 extern void pcsx2_aligned_free(void* pmem);
23
24 // aligned_malloc: Implement/declare linux equivalents here!
25 #if !defined(_MSC_VER) && !defined(HAVE_ALIGNED_MALLOC)
26 # define _aligned_malloc pcsx2_aligned_malloc
27 # define _aligned_free pcsx2_aligned_free
28 # define _aligned_realloc pcsx2_aligned_realloc
29 #endif
30
31 //////////////////////////////////////////////////////////////////////////////////////////
32 // Safe deallocation macros -- checks pointer validity (non-null) when needed, and sets
33 // pointer to null after deallocation.
34
35 #define safe_delete( ptr ) \
36 ((void) (delete (ptr)), (ptr) = NULL)
37
38 #define safe_delete_array( ptr ) \
39 ((void) (delete[] (ptr)), (ptr) = NULL)
40
41 // No checks for NULL -- wxWidgets says it's safe to skip NULL checks and it runs on
42 // just about every compiler and libc implementation of any recentness.
43 #define safe_free( ptr ) \
44 ( (void) (free( ptr ), !!0), (ptr) = NULL )
45 //((void) (( ( (ptr) != NULL ) && (free( ptr ), !!0) ), (ptr) = NULL))
46
47 #define safe_fclose( ptr ) \
48 ((void) (( ( (ptr) != NULL ) && (fclose( ptr ), !!0) ), (ptr) = NULL))
49
50 // Implementation note: all known implementations of _aligned_free check the pointer for
51 // NULL status (our implementation under GCC, and microsoft's under MSVC), so no need to
52 // do it here.
53 #define safe_aligned_free( ptr ) \
54 ((void) ( _aligned_free( ptr ), (ptr) = NULL ))
55
56 #define SafeSysMunmap( ptr, size ) \
57 ((void) ( HostSys::Munmap( (uptr)(ptr), size ), (ptr) = NULL ))
58
59 // Microsoft Windows only macro, useful for freeing out COM objects:
60 #define safe_release( ptr ) \
61 ((void) (( ( (ptr) != NULL ) && ((ptr)->Release(), !!0) ), (ptr) = NULL))
62
63 //////////////////////////////////////////////////////////////////////////////////////////
64 // Handy little class for allocating a resizable memory block, complete with
65 // exception-based error handling and automatic cleanup.
66 //
67 template< typename T >
68 class SafeArray
69 {
70 DeclareNoncopyableObject(SafeArray);
71
72 public:
73 static const int DefaultChunkSize = 0x1000 * sizeof(T);
74
75 public:
76 wxString Name; // user-assigned block name
77 int ChunkSize;
78
79 protected:
80 T* m_ptr;
81 int m_size; // size of the allocation of memory
82
83 protected:
84 // Internal constructor for use by derived classes. This allows a derived class to
85 // use its own memory allocation (with an aligned memory, for example).
86 // Throws:
87 // Exception::OutOfMemory if the allocated_mem pointer is NULL.
88 explicit SafeArray( const wxChar* name, T* allocated_mem, int initSize )
89 : Name( name )
90 {
91 ChunkSize = DefaultChunkSize;
92 m_ptr = allocated_mem;
93 m_size = initSize;
94
95 if( m_ptr == NULL )
96 throw Exception::OutOfMemory();
97 }
98
99 virtual T* _virtual_realloc( int newsize )
100 {
101 return (T*)((m_ptr == NULL) ?
102 malloc( newsize * sizeof(T) ) :
103 realloc( m_ptr, newsize * sizeof(T) )
104 );
105 }
106
107 public:
108 virtual ~SafeArray()
109 {
110 safe_free( m_ptr );
111 }
112
113 explicit SafeArray( const wxChar* name=L"Unnamed" )
114 : Name( name )
115 {
116 ChunkSize = DefaultChunkSize;
117 m_ptr = NULL;
118 m_size = 0;
119 }
120
121 explicit SafeArray( int initialSize, const wxChar* name=L"Unnamed" )
122 : Name( name )
123 {
124 ChunkSize = DefaultChunkSize;
125 m_ptr = (initialSize==0) ? NULL : (T*)malloc( initialSize * sizeof(T) );
126 m_size = initialSize;
127
128 if( (initialSize != 0) && (m_ptr == NULL) )
129 throw Exception::OutOfMemory();
130 }
131
132 // Clears the contents of the array to zero, and frees all memory allocations.
133 void Dispose()
134 {
135 m_size = 0;
136 safe_free( m_ptr );
137 }
138
139 bool IsDisposed() const { return (m_ptr==NULL); }
140
141 // Returns the size of the memory allocation, as according to the array type.
142 int GetLength() const { return m_size; }
143 // Returns the size of the memory allocation in bytes.
144 int GetSizeInBytes() const { return m_size * sizeof(T); }
145
146 // reallocates the array to the explicit size. Can be used to shrink or grow an
147 // array, and bypasses the internal threshold growth indicators.
148 void ExactAlloc( int newsize )
149 {
150 if( newsize == m_size ) return;
151
152 m_ptr = _virtual_realloc( newsize );
153 if( m_ptr == NULL )
154 {
155 throw Exception::OutOfMemory(
156 wxsFormat( // english (for diagnostic)
157 L"Out-of-memory on SafeArray block re-allocation.\n"
158 L"Old size: %d bytes, New size: %d bytes.",
159 m_size, newsize
160 ),
161 // internationalized!
162 wxsFormat( _("Out of memory, trying to allocate %d bytes."), newsize )
163 );
164 }
165 m_size = newsize;
166 }
167
168 // Ensures that the allocation is large enough to fit data of the
169 // amount requested. The memory allocation is not resized smaller.
170 void MakeRoomFor( int newsize )
171 {
172 if( newsize > m_size )
173 ExactAlloc( newsize );
174 }
175
176 // Extends the containment area of the array. Extensions are performed
177 // in chunks.
178 void GrowBy( int items )
179 {
180 MakeRoomFor( m_size + ChunkSize + items + 1 );
181 }
182
183 // Gets a pointer to the requested allocation index.
184 // DevBuilds : Generates assertion if the index is invalid.
185 T *GetPtr( uint idx=0 ) { return _getPtr( idx ); }
186 const T *GetPtr( uint idx=0 ) const { return _getPtr( idx ); }
187
188 // Gets an element of this memory allocation much as if it were an array.
189 // DevBuilds : Generates assertion if the index is invalid.
190 T& operator[]( int idx ) { return *_getPtr( (uint)idx ); }
191 const T& operator[]( int idx ) const { return *_getPtr( (uint)idx ); }
192
193 virtual SafeArray<T>* Clone() const
194 {
195 SafeArray<T>* retval = new SafeArray<T>( m_size );
196 memcpy_fast( retval->GetPtr(), m_ptr, sizeof(T) * m_size );
197 return retval;
198 }
199
200 protected:
201 // A safe array index fetcher. Throws an exception if the array index
202 // is outside the bounds of the array.
203 // Performance Considerations: This function adds quite a bit of overhead
204 // to array indexing and thus should be done infrequently if used in
205 // time-critical situations. Instead of using it from inside loops, cache
206 // the pointer into a local variable and use std (unsafe) C indexes.
207 T* _getPtr( uint i ) const
208 {
209 IndexBoundsCheckDev( Name.c_str(), i, m_size );
210 return &m_ptr[i];
211 }
212 };
213
214 //////////////////////////////////////////////////////////////////////////////////////////
215 // SafeList - Simple growable container without all the mess or hassle of std containers.
216 //
217 // This container is intended for reasonably simple class types only. Things which this
218 // container does not handle with desired robustness:
219 //
220 // * Classes with non-trivial constructors (such that construction creates much overhead)
221 // * Classes with copy constructors (copying is done using performance memcpy)
222 // * Classes with destructors (they're not called, sorry!)
223 //
224 template< typename T >
225 class SafeList
226 {
227 DeclareNoncopyableObject(SafeList);
228
229 public:
230 static const int DefaultChunkSize = 0x80 * sizeof(T);
231
232 public:
233 wxString Name; // user-assigned block name
234 int ChunkSize; // assigned DefaultChunkSize on init, reconfigurable at any time.
235
236 protected:
237 T* m_ptr;
238 int m_allocsize; // size of the allocation of memory
239 uint m_length; // length of the array (active items, not buffer allocation)
240
241 protected:
242 virtual T* _virtual_realloc( int newsize )
243 {
244 return (T*)realloc( m_ptr, newsize * sizeof(T) );
245 }
246
247 public:
248 virtual ~SafeList() throw()
249 {
250 safe_free( m_ptr );
251 }
252
253 explicit SafeList( const wxChar* name=L"Unnamed" ) :
254 Name( name )
255 , ChunkSize( DefaultChunkSize )
256 , m_ptr( NULL )
257 , m_allocsize( 0 )
258 , m_length( 0 )
259 {
260 }
261
262 explicit SafeList( int initialSize, const wxChar* name=L"Unnamed" ) :
263 Name( name )
264 , ChunkSize( DefaultChunkSize )
265 , m_ptr( (T*)malloc( initialSize * sizeof(T) ) )
266 , m_allocsize( initialSize )
267 , m_length( 0 )
268 {
269 if( m_ptr == NULL )
270 throw Exception::OutOfMemory();
271
272 for( int i=0; i<m_allocsize; ++i )
273 {
274 new (&m_ptr[i]) T();
275 }
276
277 }
278
279 // Returns the size of the list, as according to the array type. This includes
280 // mapped items only. The actual size of the allocation may differ.
281 int GetLength() const { return m_length; }
282
283 // Returns the size of the list, in bytes. This includes mapped items only.
284 // The actual size of the allocation may differ.
285 int GetSizeInBytes() const { return m_length * sizeof(T); }
286
287 void MatchLengthToAllocatedSize()
288 {
289 m_length = m_allocsize;
290 }
291
292 // Ensures that the allocation is large enough to fit data of the
293 // amount requested. The memory allocation is not resized smaller.
294 void MakeRoomFor( int blockSize )
295 {
296 if( blockSize > m_allocsize )
297 {
298 const int newalloc = blockSize + ChunkSize;
299 m_ptr = _virtual_realloc( newalloc );
300 if( m_ptr == NULL )
301 {
302 throw Exception::OutOfMemory(
303 // English Diagnostic message:
304 wxsFormat(
305 L"Out-of-memory on SafeList block re-allocation.\n"
306 L"Name: %s, Old size: %d bytes, New size: %d bytes",
307 Name.c_str(), m_allocsize, newalloc
308 ),
309
310 wxsFormat( _("Out of memory, trying to allocate %d bytes."), newalloc )
311 );
312 }
313
314 for( ; m_allocsize<newalloc; ++m_allocsize )
315 {
316 new (&m_ptr[m_allocsize]) T();
317 }
318 }
319 }
320
321 void GrowBy( int items )
322 {
323 MakeRoomFor( m_length + ChunkSize + items + 1 );
324 }
325
326 // Sets the item length to zero. Does not free memory allocations.
327 void Clear()
328 {
329 m_length = 0;
330 }
331
332 // Appends an item to the end of the list and returns a handle to it.
333 T& New()
334 {
335 _MakeRoomFor_threshold( m_length + 1 );
336 return m_ptr[m_length++];
337 }
338
339 // Gets an element of this memory allocation much as if it were an array.
340 // DevBuilds : Generates assertion if the index is invalid.
341 T& operator[]( int idx ) { return *_getPtr( (uint)idx ); }
342 const T& operator[]( int idx ) const { return *_getPtr( (uint)idx ); }
343
344 T* GetPtr() { return m_ptr; }
345 const T* GetPtr() const { return m_ptr; }
346
347 T& GetLast() { return m_ptr[m_length-1]; }
348 const T& GetLast() const{ return m_ptr[m_length-1]; }
349
350 int Add( const T& src )
351 {
352 _MakeRoomFor_threshold( m_length + 1 );
353 m_ptr[m_length] = src;
354 return m_length++;
355 }
356
357 // Same as Add, but returns the handle of the new object instead of it's array index.
358 T& AddNew( const T& src )
359 {
360 _MakeRoomFor_threshold( m_length + 1 );
361 m_ptr[m_length] = src;
362 return m_ptr[m_length];
363 }
364
365 // Performs a standard array-copy removal of the given item. All items past the
366 // given item are copied over.
367 // DevBuilds : Generates assertion if the index is invalid.
368 void Remove( int index )
369 {
370 IndexBoundsCheckDev( Name.c_str(), index, m_length );
371
372 int copylen = m_length - index;
373 if( copylen > 0 )
374 memcpy_fast( &m_ptr[index], &m_ptr[index+1], copylen );
375 }
376
377 virtual SafeList<T>* Clone() const
378 {
379 SafeList<T>* retval = new SafeList<T>( m_length );
380 memcpy_fast( retval->m_ptr, m_ptr, sizeof(T) * m_length );
381 return retval;
382 }
383
384 protected:
385
386 void _MakeRoomFor_threshold( int newsize )
387 {
388 MakeRoomFor( newsize + ChunkSize );
389 }
390
391 // A safe array index fetcher. Throws an exception if the array index
392 // is outside the bounds of the array.
393 // Performance Considerations: This function adds quite a bit of overhead
394 // to array indexing and thus should be done infrequently if used in
395 // time-critical situations. Instead of using it from inside loops, cache
396 // the pointer into a local variable and use std (unsafe) C indexes.
397 T* _getPtr( uint i ) const
398 {
399 IndexBoundsCheckDev( Name.c_str(), i, m_length );
400 return &m_ptr[i];
401 }
402 };
403
404 // --------------------------------------------------------------------------------------
405 // SafeAlignedArray class
406 // --------------------------------------------------------------------------------------
407 // Handy little class for allocating a resizable memory block, complete with
408 // exception-based error handling and automatic cleanup.
409 // This one supports aligned data allocations too!
410
411 template< typename T, uint Alignment >
412 class SafeAlignedArray : public SafeArray<T>
413 {
414 protected:
415 T* _virtual_realloc( int newsize )
416 {
417 return (T*)( ( this->m_ptr == NULL ) ?
418 _aligned_malloc( newsize * sizeof(T), Alignment ) :
419 _aligned_realloc( this->m_ptr, newsize * sizeof(T), Alignment )
420 );
421 }
422
423 // Appends "(align: xx)" to the name of the allocation in devel builds.
424 // Maybe useful,maybe not... no harm in attaching it. :D
425
426 public:
427 virtual ~SafeAlignedArray()
428 {
429 safe_aligned_free( this->m_ptr );
430 // mptr is set to null, so the parent class's destructor won't re-free it.
431 }
432
433 explicit SafeAlignedArray( const wxChar* name=L"Unnamed" ) :
434 SafeArray<T>::SafeArray( name )
435 {
436 }
437
438 explicit SafeAlignedArray( int initialSize, const wxChar* name=L"Unnamed" ) :
439 SafeArray<T>::SafeArray(
440 name,
441 (T*)_aligned_malloc( initialSize * sizeof(T), Alignment ),
442 initialSize
443 )
444 {
445 }
446
447 virtual SafeAlignedArray<T,Alignment>* Clone() const
448 {
449 SafeAlignedArray<T,Alignment>* retval = new SafeAlignedArray<T,Alignment>( this->m_size );
450 memcpy_fast( retval->GetPtr(), this->m_ptr, sizeof(T) * this->m_size );
451 return retval;
452 }
453 };
454
455
456 // For lack of a better place for now (they depend on SafeList so they can't go in StringUtil)
457 extern void SplitString( SafeList<wxString>& dest, const wxString& src, const wxString& delims );
458 extern void JoinString( wxString& dest, const SafeList<wxString>& src, const wxString& separator );

  ViewVC Help
Powered by ViewVC 1.1.22