/[pcsx2_0.9.7]/trunk/common/src/Utilities/FastFormatString.cpp
ViewVC logotype

Annotation of /trunk/common/src/Utilities/FastFormatString.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (hide annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 1 month ago) by william
File size: 10538 byte(s)
re-commit (had local access denied errors when committing)
1 william 31 /* 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     #include "PrecompiledHeader.h"
17     #include "Threading.h"
18 william 273
19 william 62 #include "TlsVariable.inl"
20     #include "SafeArray.inl"
21 william 31
22     using namespace Threading;
23    
24 william 62 // Implement some very commonly used SafeArray types here
25     // (done here for lack of a better place)
26    
27     template class SafeArray<char>;
28     template class SafeArray<wchar_t>;
29     template class SafeArray<u8>;
30    
31     template class SafeAlignedArray<char,16>;
32     template class SafeAlignedArray<wchar_t,16>;
33     template class SafeAlignedArray<u8,16>;
34    
35 william 31 // Sanity check: truncate strings if they exceed 512k in length. Anything like that
36     // is either a bug or really horrible code that needs to be stopped before it causes
37     // system deadlock.
38     static const int MaxFormattedStringLength = 0x80000;
39    
40 william 273 typedef ScopedAlignedAlloc<char,16> CharBufferType;
41    
42 william 31 // --------------------------------------------------------------------------------------
43 william 62 // FastFormatBuffers
44 william 31 // --------------------------------------------------------------------------------------
45 william 273 // This class provides a series of pre-allocated thread-local buffers for use by string
46     // formatting tools. These buffers are handed out in round-robin style and require *no*
47     // thread sync objects and avoid multi-thread contention completely -- allowing multiple
48     // threads to format complicated strings concurrently with maximum efficiency.
49     //
50 william 62 class FastFormatBuffers
51 william 31 {
52 william 62 DeclareNoncopyableObject(FastFormatBuffers);
53    
54     protected:
55 william 273 typedef char CharType;
56     typedef CharBufferType BufferType;
57 william 62
58 william 280 static const uint BufferCount = 6;
59 william 62
60     BufferType m_buffers[BufferCount];
61     uint m_curslot;
62    
63 william 31 public:
64 william 62 FastFormatBuffers()
65     {
66     // This protects against potential recursive calls to our formatter, by forcing those
67     // calls to use a dynamic buffer for formatting.
68     m_curslot = BufferCount;
69 william 31
70 william 62 for (uint i=0; i<BufferCount; ++i)
71     {
72 william 280 m_buffers[i].Alloc(512);
73 william 62 }
74    
75     m_curslot = 0;
76     }
77    
78     virtual ~FastFormatBuffers() throw()
79 william 31 {
80 william 273 pxAssumeDev(m_curslot==0,
81     wxsFormat(L"Dangling %s formatting buffer detected!",
82     (sizeof(CharType)==1) ? L"UTF8/Ascii" : L"Wide-char"
83     )
84     );
85 william 31 }
86    
87 william 62 bool HasFreeBuffer() const
88 william 31 {
89 william 62 return m_curslot < BufferCount-1;
90 william 31 }
91 william 62
92     BufferType& GrabBuffer()
93     {
94     ++m_curslot;
95 william 273 pxAssume(m_curslot < BufferCount);
96 william 62 return m_buffers[m_curslot];
97     }
98    
99     void ReleaseBuffer()
100     {
101     --m_curslot;
102 william 273 pxAssume(m_curslot < BufferCount);
103 william 62 }
104    
105     BufferType& operator[](uint i)
106     {
107     IndexBoundsAssume( ((sizeof(CharType)==1) ? L"Ascii Formatting Buffer" : L"Unicode Formatting Buffer"), i, BufferCount );
108     return m_buffers[i];
109     }
110 william 31 };
111    
112 william 62 // --------------------------------------------------------------------------------------
113     // GlobalBufferManager
114     // --------------------------------------------------------------------------------------
115     // This local-scope class is needed in order to safely deal with C++ initializing and destroying
116     // global objects in arbitrary order. The initbit is updated by the object when constructed and
117     // destroyed; code using this class provides its own statically-initialized boolean (which MUST
118     // default to false!) and then sets the boolean to true to indicate the object is ready for use.
119     //
120     template< typename T >
121     class GlobalBufferManager
122     {
123     public:
124     bool& initbit;
125     T instance;
126 william 31
127 william 62 GlobalBufferManager( bool& globalBoolean )
128     : initbit( globalBoolean )
129     {
130     initbit = true;
131     }
132    
133     ~GlobalBufferManager() throw()
134     {
135     initbit = false;
136     instance.Dispose();
137     }
138 william 31
139 william 62 T& Get()
140     {
141     return instance;
142     }
143 william 31
144 william 62 operator T&()
145     {
146     return instance;
147     }
148     };
149    
150     static bool buffer_is_avail = false;
151 william 273 static GlobalBufferManager< BaseTlsVariable< FastFormatBuffers > > m_buffer_tls(buffer_is_avail);
152 william 62
153 william 273 //static __ri void format_that_ascii_mess( SafeArray<char>& buffer, uint writepos, const char* fmt, va_list argptr )
154     static __ri void format_that_ascii_mess( CharBufferType& buffer, uint writepos, const char* fmt, va_list argptr )
155 william 31 {
156     while( true )
157     {
158     int size = buffer.GetLength();
159 william 62 int len = vsnprintf(buffer.GetPtr(writepos), size-writepos, fmt, argptr);
160 william 31
161     // some implementations of vsnprintf() don't NUL terminate
162     // the string if there is not enough space for it so
163     // always do it manually
164     buffer[size-1] = '\0';
165    
166 william 62 if (size >= MaxFormattedStringLength) break;
167 william 31
168     // vsnprintf() may return either -1 (traditional Unix behavior) or the
169     // total number of characters which would have been written if the
170     // buffer were large enough (newer standards such as Unix98)
171    
172 william 62 if (len < 0)
173 william 31 len = size + (size/4);
174    
175 william 62 len += writepos;
176     if (len < size) break;
177 william 280 buffer.Resize( len + 128 );
178 william 31 };
179    
180     // performing an assertion or log of a truncated string is unsafe, so let's not; even
181     // though it'd be kinda nice if we did.
182     }
183    
184 william 273 // returns the length of the formatted string, in characters (wxChars).
185     static __ri uint format_that_unicode_mess( CharBufferType& buffer, uint writepos, const wxChar* fmt, va_list argptr)
186 william 31 {
187     while( true )
188     {
189 william 62 int size = buffer.GetLength() / sizeof(wxChar);
190 william 273 int len = wxVsnprintf((wxChar*)buffer.GetPtr(writepos*sizeof(wxChar)), size-writepos, fmt, argptr);
191 william 31
192     // some implementations of vsnprintf() don't NUL terminate
193     // the string if there is not enough space for it so
194     // always do it manually
195 william 62 ((wxChar*)buffer.GetPtr())[size-1] = L'\0';
196 william 31
197 william 273 if( size >= MaxFormattedStringLength ) return size-1;
198 william 31
199     // vsnprintf() may return either -1 (traditional Unix behavior) or the
200     // total number of characters which would have been written if the
201     // buffer were large enough (newer standards such as Unix98)
202    
203 william 62 if (len < 0)
204 william 31 len = size + (size/4);
205    
206 william 62 len += writepos;
207 william 273 if (len < size) return len;
208 william 280 buffer.Resize( (len + 128) * sizeof(wxChar) );
209 william 31 };
210    
211     // performing an assertion or log of a truncated string is unsafe, so let's not; even
212     // though it'd be kinda nice if we did.
213 william 273
214     pxAssume( false );
215     return 0; // unreachable.
216 william 31 }
217    
218 william 273 CharBufferType* GetFormatBuffer( bool& deleteDest )
219 william 31 {
220 william 62 deleteDest = false;
221     if (buffer_is_avail)
222 william 31 {
223 william 62 if (m_buffer_tls.Get()->HasFreeBuffer())
224     return &m_buffer_tls.Get()->GrabBuffer();
225 william 31 }
226 william 62
227     deleteDest = true;
228 william 273
229     return new CharBufferType(2048);
230 william 62 }
231    
232     // --------------------------------------------------------------------------------------
233     // FastFormatUnicode (implementations)
234     // --------------------------------------------------------------------------------------
235 william 273 // [TODO] This class should actually be renamed to FastFormatNative or FastFormatString, and
236     // adopted to properly support 1-byte wxChar types (mostly requiring some changes to the
237     // WriteV functions). The current implementation is fine for wx2.8, which always defaults
238     // to wide-varieties of wxChar -- but wx3.0 will use UTF8 for linux distros, which will break
239     // this class nicely in its current state. --air
240    
241 william 62 FastFormatUnicode::FastFormatUnicode()
242     {
243     m_dest = GetFormatBuffer(m_deleteDest);
244 william 273 Clear();
245 william 62 }
246    
247     FastFormatUnicode::~FastFormatUnicode() throw()
248     {
249     if (m_deleteDest)
250     delete m_dest;
251 william 31 else
252 william 62 m_buffer_tls.Get()->ReleaseBuffer();
253     }
254 william 31
255 william 273 void FastFormatUnicode::Clear()
256     {
257     m_Length = 0;
258     ((wxChar*)m_dest->GetPtr())[0] = 0;
259     }
260    
261 william 62 FastFormatUnicode& FastFormatUnicode::WriteV( const char* fmt, va_list argptr )
262     {
263     wxString converted( fromUTF8(FastFormatAscii().WriteV( fmt, argptr )) );
264    
265 william 273 const uint inspos = m_Length;
266     const uint convLen = converted.Length();
267     m_dest->MakeRoomFor((inspos + convLen + 64) * sizeof(wxChar));
268     memcpy_fast( &((wxChar*)m_dest->GetPtr())[inspos], converted, (convLen+1)*sizeof(wxChar) );
269     m_Length += convLen;
270    
271 william 62 return *this;
272 william 31 }
273    
274 william 62 FastFormatUnicode& FastFormatUnicode::WriteV( const wxChar* fmt, va_list argptr )
275 william 31 {
276 william 273 m_Length = format_that_unicode_mess( *m_dest, m_Length, fmt, argptr );
277 william 62 return *this;
278     }
279    
280     FastFormatUnicode& FastFormatUnicode::Write( const char* fmt, ... )
281     {
282     va_list list;
283     va_start(list, fmt);
284     WriteV(fmt,list);
285     va_end(list);
286     return *this;
287     }
288    
289     FastFormatUnicode& FastFormatUnicode::Write( const wxChar* fmt, ... )
290     {
291     va_list list;
292     va_start(list, fmt);
293     WriteV(fmt,list);
294     va_end(list);
295     return *this;
296     }
297    
298     bool FastFormatUnicode::IsEmpty() const
299     {
300     return ((wxChar&)(*m_dest)[0]) == 0;
301     }
302    
303 william 273 FastFormatUnicode& FastFormatUnicode::ToUpper()
304     {
305     wxChar* ch = (wxChar*)m_dest->GetPtr();
306     for ( uint i=0; i<m_Length; ++i, ++ch )
307     *ch = (wxChar)wxToupper(*ch);
308    
309     return *this;
310     }
311    
312     FastFormatUnicode& FastFormatUnicode::ToLower()
313     {
314     wxChar* ch = (wxChar*)m_dest->GetPtr();
315     for ( uint i=0; i<m_Length; ++i, ++ch )
316     *ch = (wxChar)wxTolower(*ch);
317    
318     return *this;
319     }
320    
321     FastFormatUnicode& FastFormatUnicode::operator+=(const char* psz )
322     {
323     Write( L"%s", fromUTF8(psz).c_str() );
324     return *this;
325     }
326    
327     wxString& operator+=(wxString& str1, const FastFormatUnicode& str2)
328     {
329     str1.Append(str2.c_str(), str2.Length());
330     return str1;
331     }
332    
333     wxString operator+(const wxString& str1, const FastFormatUnicode& str2)
334     {
335     wxString s = str1;
336     s += str2;
337    
338     return s;
339     }
340    
341     wxString operator+(const wxChar* str1, const FastFormatUnicode& str2)
342     {
343     wxString s = str1;
344     s += str2;
345    
346     return s;
347     }
348    
349    
350 william 62 // --------------------------------------------------------------------------------------
351     // FastFormatAscii (implementations)
352     // --------------------------------------------------------------------------------------
353     FastFormatAscii::FastFormatAscii()
354     {
355     m_dest = GetFormatBuffer(m_deleteDest);
356 william 273 Clear();
357 william 62 }
358    
359     FastFormatAscii::~FastFormatAscii() throw()
360     {
361     if (m_deleteDest)
362     delete m_dest;
363 william 31 else
364 william 62 m_buffer_tls.Get()->ReleaseBuffer();
365 william 31 }
366 william 62
367 william 273 void FastFormatAscii::Clear()
368 william 62 {
369 william 273 m_dest->GetPtr()[0] = 0;
370 william 62 }
371    
372 william 273 const wxString FastFormatAscii::GetString() const
373 william 62 {
374     return fromAscii(m_dest->GetPtr());
375 william 273 }
376 william 62
377     FastFormatAscii& FastFormatAscii::WriteV( const char* fmt, va_list argptr )
378     {
379     format_that_ascii_mess( *m_dest, strlen(m_dest->GetPtr()), fmt, argptr );
380     return *this;
381     }
382    
383     FastFormatAscii& FastFormatAscii::Write( const char* fmt, ... )
384     {
385     va_list list;
386     va_start(list, fmt);
387     WriteV(fmt,list);
388     va_end(list);
389     return *this;
390     }
391    
392    
393     bool FastFormatAscii::IsEmpty() const
394     {
395     return (*m_dest)[0] == 0;
396     }

  ViewVC Help
Powered by ViewVC 1.1.22