My Project
StringBuilder.hpp
1 //-----------------------------------------------------------------------------
2 // Class: StringBuilderT
3 // Authors: LiXizhi
4 // Emails: LiXizhi@yeah.net
5 // Company: ParaEngine corporation
6 // Date: 2008.6.16
7 // Desc:
8 // Portions of the code are:
9 // Copyright (C) 2005-2007 Feeling Software Inc.
10 // Copyright (C) 2005-2007 Sony Computer Entertainment America
11 //
12 // MIT License: http://www.opensource.org/licenses/mit-license.php
13 //-----------------------------------------------------------------------------
14 #include "math/ParaMath.h"
15 
16 #include <limits>
17 
18 #ifdef WIN32
19 #include <float.h>
20 #endif
21 
22 #ifdef WIN32
23 #define ecvt _ecvt
24 #endif // WIN32
25 #ifdef ANDROID
26 #include <math.h>
27 #include <stdlib.h>
28 
29 #define NDIG 80
30 
31 static char * cvt(double arg, int ndigits, int* decpt, int *sign, int eflag)
32 {
33  int r2;
34  double fi, fj;
35  register char *p, *p1;
36  static char buf[NDIG];
37 
38  if (ndigits < 0)
39  ndigits = 0;
40  if (ndigits >= NDIG - 1)
41  ndigits = NDIG - 2;
42  r2 = 0;
43  *sign = 0;
44  p = &buf[0];
45  if (arg < 0) {
46  *sign = 1;
47  arg = -arg;
48  }
49  arg = modf(arg, &fi);
50  p1 = &buf[NDIG];
51  /*
52  * Do integer part
53  */
54  if (fi != 0) {
55  p1 = &buf[NDIG];
56  while (fi != 0) {
57  fj = modf(fi / 10, &fi);
58  *--p1 = (int)((fj + .03) * 10) + '0';
59  r2++;
60  }
61  while (p1 < &buf[NDIG])
62  *p++ = *p1++;
63  }
64  else if (arg > 0) {
65  while ((fj = arg * 10) < 1) {
66  arg = fj;
67  r2--;
68  }
69  }
70  p1 = &buf[ndigits];
71  if (eflag == 0)
72  p1 += r2;
73  *decpt = r2;
74  if (p1 < &buf[0]) {
75  buf[0] = '\0';
76  return(buf);
77  }
78  while (p <= p1 && p < &buf[NDIG]) {
79  arg *= 10;
80  arg = modf(arg, &fj);
81  *p++ = (int)fj + '0';
82  }
83  if (p1 >= &buf[NDIG]) {
84  buf[NDIG - 1] = '\0';
85  return(buf);
86  }
87  p = p1;
88  *p1 += 5;
89  while (*p1 > '9') {
90  *p1 = '0';
91  if (p1 > buf)
92  ++*--p1;
93  else {
94  *p1 = '1';
95  (*decpt)++;
96  if (eflag == 0) {
97  if (p > buf)
98  *p = '0';
99  p++;
100  }
101  }
102  }
103  *p = '\0';
104  return(buf);
105 }
106 
107 char * ecvt(double arg, int ndigits, int *decpt, int *sign)
108 {
109  return cvt(arg, ndigits, decpt, sign, 1);
110 }
111 
112 char * fcvt(double arg, int ndigits, int*decpt, int * sign)
113 {
114  return cvt(arg, ndigits, decpt, sign, 0);
115 }
116 #endif
117 namespace ParaEngine
118 {
119 
120  template <class Char, class FloatType>
121  void FloatToString(FloatType f, Char* sz)
122  {
123  Char* sBuffer = sz + 1;
124  static const int digitCount = 6;
125  int decimal, sign;
126 
127  // ecvt rounds the string for us: http://www.datafocus.com/docs/man3/ecvt.3.asp
128  char* end = ecvt(f, digitCount, &decimal, &sign);
129 
130  if (sign != 0) (*sBuffer++) = '-';
131  int count = digitCount;
132  if (decimal > digitCount)
133  {
134  // We use the scientific notation: P.MeX
135  (*sBuffer++) = (*end++); // P is one character.
136  (*sBuffer++) = '.';
137 
138  // Mantissa (cleaned for zeroes)
139  for (--count; count > 0; --count) if (end[count - 1] != '0') break;
140  for (int i = 0; i < count; ++i) (*sBuffer++) = (*end++);
141  if (sBuffer[-1] == '.') --sBuffer;
142 
143  // Exponent
144  (*sBuffer++) = 'e';
145  uint32 exponent = decimal - 1; // X
146  if (exponent >= 10) (*sBuffer++) = (Char)('0' + (exponent / 10));
147  (*sBuffer++) = (Char)('0' + (exponent % 10));
148  (*sBuffer) = 0;
149  return;
150  }
151  else if (decimal > 0)
152  {
153  // Simple number: A.B
154  for (int i = 0; i < decimal; ++i) (*sBuffer++) = (*end++);
155  if (decimal < digitCount) (*sBuffer++) = '.';
156  count = digitCount - decimal;
157  }
158  else if (decimal < -digitCount)
159  {
160  // What case is this?
161  decimal = count = 0;
162  }
163  else if (decimal < 0 || (decimal == 0 && *end != '0'))
164  {
165  // Tiny number: 0.Me-X
166  (*sBuffer++) = '0'; (*sBuffer++) = '.';
167  for (int i = 0; i < -decimal; ++i) (*sBuffer++) = '0';
168  count = digitCount + decimal;
169  }
170  for (; count > 0; --count) if (end[count - 1] != '0') break;
171  for (int i = 0; i < count; ++i) (*sBuffer++) = (*end++);
172  if (decimal == 0 && count == 0) (*sBuffer++) = '0';
173  if (sBuffer[-1] == '.') --sBuffer;
174  (*sBuffer) = 0;
175  }
176 
177 
178  template <typename UserAllocator>
180  {
181  this->m_buffer = NULL;
182  this->m_size = 0;
183  this->m_reserved = 0;
184 
185  append(sz.c_str(), sz.size());
186  }
187 
188  template <typename UserAllocator>
190  {
191  this->m_buffer = NULL;
192  this->m_size = 0;
193  this->m_reserved = 0;
194 
195  size_t len = 0;
196  for (const Char* p = sz; *p != 0; ++p) ++len;
197  append(sz, len);
198  }
199 
200  template <typename UserAllocator>
202  {
203  this->m_buffer = NULL;
204  this->m_size = 0;
205  this->m_reserved = 0;
206 
207  reserve(count);
208  for (size_t i = 0; i < count; ++i) m_buffer[m_size++] = ch;
209  }
210 
211  template <typename UserAllocator>
213  {
214  this->m_buffer = NULL;
215  this->m_size = 0;
216  this->m_reserved = 0;
217  reserve(reservation);
218  }
219 
220  template <typename UserAllocator>
222  {
223  this->m_buffer = NULL;
224  this->m_size = 0;
225  this->m_reserved = 0;
226  }
227 
228  template <typename UserAllocator>
230  {
231  reserve(0);
232  }
233 
234  template <typename UserAllocator>
235  void StringBuilderT<UserAllocator>::enlarge(size_t minimum)
236  {
237  reserve(max(m_reserved + minimum, 2 * m_reserved));
238  }
239 
240  template <typename UserAllocator>
242  {
243  m_size = 0;
244  }
245 
246  template <typename UserAllocator>
248  {
249  if (new_size > m_reserved)
250  {
251  reserve(new_size);
252  }
253  m_size = new_size;
254  }
255 
256  template <typename UserAllocator>
258  {
259  if (m_size + 1 >= m_reserved) enlarge(2);
260 
261  m_buffer[m_size++] = c;
262  }
263 
264  template <typename UserAllocator>
265  void StringBuilderT<UserAllocator>::append(const string_type& sz) { append(sz.c_str()); }
266  template <typename UserAllocator>
268  {
269  if (sz == NULL) return;
270 
271  // This is optimized for SMALL strings.
272  for (; *sz != 0; ++sz)
273  {
274  if (m_size >= m_reserved) enlarge(32);
275  m_buffer[m_size++] = *sz;
276  }
277  }
278  template <typename UserAllocator>
279  void StringBuilderT<UserAllocator>::append(const Char* sz, size_t len)
280  {
281  if (sz == NULL) return;
282 
283  if ((m_size + len) >= m_reserved)
284  {
285  enlarge(max((size_t)32, m_size + len + 1));
286  }
287  memcpy(m_buffer + m_size, sz, len);
288  m_size += len;
289  }
290 
291  template <typename UserAllocator>
292  void StringBuilderT<UserAllocator>::WriteAt(int nIndex, const Char* sz, size_t len)
293  {
294  if (sz == NULL || len == 0) return;
295 
296  if ((len + nIndex) > m_size)
297  {
298  if ((len + nIndex) >= m_reserved)
299  {
300  enlarge(max((size_t)32, nIndex + len + 1));
301  }
302  m_size = nIndex + len;
303  }
304  memcpy(m_buffer + nIndex, sz, len);
305  }
306 
307 
308  template <typename UserAllocator>
310  {
311  if (m_size + b.m_size >= m_reserved) enlarge(32 + m_size + b.m_size - m_reserved);
312  memcpy(m_buffer + m_size, b.m_buffer, b.m_size * sizeof(Char));
313  m_size += b.m_size;
314  }
315 
316  template <typename UserAllocator>
318  {
319 #ifdef WIN32
320  // use <float.h> _isnan method to detect the 1.#IND00 NaN.
321  if (f != std::numeric_limits<float>::infinity() && f != -std::numeric_limits<float>::infinity() && f != std::numeric_limits<float>::quiet_NaN() && f != std::numeric_limits<float>::signaling_NaN() && !_isnan((double)f))
322 #else
323  if (f != std::numeric_limits<float>::infinity() && f != -std::numeric_limits<float>::infinity() && f != std::numeric_limits<float>::quiet_NaN() && f != std::numeric_limits<float>::signaling_NaN())
324 #endif
325  {
326  if (Math::IsEquivalent(f, 0.0f, std::numeric_limits<float>::epsilon())) append((Char)'0');
327  else
328  {
329  Char sz[128];
330  FloatToString(f, sz);
331  append(sz + 1);
332  }
333  }
334  else if (f == std::numeric_limits<float>::infinity())
335  {
336  append((Char)'I'); append((Char)'N'); append((Char)'F');
337  }
338  else if (f == -std::numeric_limits<float>::infinity())
339  {
340  append((Char)'-'); append((Char)'I'); append((Char)'N'); append((Char)'F');
341  }
342  else
343  {
344  append((Char)'N'); append((Char)'a'); append((Char)'N');
345  }
346  }
347 
348  template <typename UserAllocator>
350  {
351 #ifdef WIN32
352  // use <float.h> _isnan method to detect the .#IND00 NaN.
353  if (f != std::numeric_limits<float>::infinity() && f != -std::numeric_limits<float>::infinity() && f != std::numeric_limits<float>::quiet_NaN() && f != std::numeric_limits<float>::signaling_NaN() && !_isnan(f))
354 #else
355  if (f != std::numeric_limits<float>::infinity() && f != -std::numeric_limits<float>::infinity() && f != std::numeric_limits<float>::quiet_NaN() && f != std::numeric_limits<float>::signaling_NaN())
356 #endif
357  {
358  if (Math::IsEquivalent(f, 0.0, std::numeric_limits<double>::epsilon())) append((Char)'0');
359  else
360  {
361  Char sz[128];
362  FloatToString(f, sz);
363  append(sz + 1);
364  }
365  }
366  else if (f == std::numeric_limits<double>::infinity())
367  {
368  append((Char)'I'); append((Char)'N'); append((Char)'F');
369  }
370  else if (f == -std::numeric_limits<double>::infinity())
371  {
372  append((Char)'-'); append((Char)'I'); append((Char)'N'); append((Char)'F');
373  }
374  else
375  {
376  append((Char)'N'); append((Char)'a'); append((Char)'N');
377  }
378  }
379 
380  template <typename UserAllocator>
382  {
383  append(sz);
384  append((Char)'\n');
385  }
386 
387  template <typename UserAllocator>
389  {
390  uint8 top = (i & 0xF0) >> 4;
391  uint8 bot = i & 0xF;
392  if (top <= 0x9) append((Char)('0' + top));
393  else append((Char)('A' + (top - 0xA)));
394  if (bot <= 0x9) append((Char)('0' + bot));
395  else append((Char)('A' + (bot - 0xA)));
396  }
397 
398  template <typename UserAllocator>
400  {
401  if ((int32)m_size > start && start >= 0) m_size = start;
402  }
403 
404  template <typename UserAllocator>
405  void StringBuilderT<UserAllocator>::remove(int32 start, int32 end)
406  {
407  int32 diff = end - start;
408  if ((int32)m_size >= end && start >= 0 && diff > 0)
409  {
410  const Char* stop = m_buffer + m_size - diff;
411  for (Char* p = m_buffer + start; p != stop; ++p)
412  {
413  *p = *(p + diff);
414  }
415  m_size -= diff;
416  }
417  }
418 
419  template <typename UserAllocator>
420  const typename StringBuilderT<UserAllocator>::Char* StringBuilderT<UserAllocator>::c_str() const
421  {
422  StringBuilderT<UserAllocator>* ncThis = const_cast< StringBuilderT<UserAllocator>* >(this);
423  if (m_size + 1 > m_reserved) ncThis->enlarge(1);
424  ncThis->m_buffer[m_size] = 0;
425  return m_buffer;
426  }
427 
428  template <typename UserAllocator>
430  {
431  if (m_buffer != NULL && m_size > 0)
432  {
433  const Char* end = m_buffer + m_size + 1;
434  for (const Char* p = m_buffer; p != end; ++p)
435  {
436  if (*p == c) return (int32)(p - m_buffer);
437  }
438  }
439  return -1;
440  }
441 
442  template <typename UserAllocator>
444  {
445  if (m_buffer != NULL && m_size > 0)
446  {
447  for (const Char* p = m_buffer + m_size - 1; p != m_buffer; --p)
448  {
449  if (*p == c) return (int32)(p - m_buffer);
450  }
451  }
452  return -1;
453  }
454 
455  template <typename UserAllocator>
457  {
458  char sz[128];
459  snprintf(sz, 128, "%u", (unsigned int)i);
460  append(sz);
461  }
462 
463  template <typename UserAllocator>
465  {
466  char sz[128];
467  snprintf(sz, 128, "%u", (unsigned int)i);
468  append(sz);
469  }
470 
471  template <typename UserAllocator>
473  {
474  char sz[128];
475  snprintf(sz, 128, "%i", (int)i);
476  append(sz);
477  }
478 
479  template <typename UserAllocator>
481  {
482  assert(m_size <= m_reserved);
483  if (_length == 0)
484  {
485  if (m_buffer != 0)
486  {
487  user_allocator::deallocate(m_buffer, m_reserved);
488  m_buffer = 0;
489  }
490  m_size = m_reserved = 0;
491  }
492  else if (_length < m_reserved)
493  {
494  if (m_size>_length)
495  m_size = _length;
496  }
497  else if (_length > m_reserved)
498  {
499  // rounded to exponent of 2, for buffer smaller than 2048
500  int n = max(5, Math::log2_ceil((int)_length)); // the smallest buffer is 32 bytes
501  if (n<11)
502  _length = (size_t)(0x1 << n);
503  else
504  {
505  // always round to multiple of 2 even for size bigger than 2048
506  _length = (size_t)(0x1 << n);
507  }
508 
509  Char* b = static_cast<Char*>(user_allocator::allocate(_length));
510  memcpy(b, m_buffer, m_size * sizeof(Char));
511  if (m_buffer != 0)
512  {
513  user_allocator::deallocate(m_buffer, m_reserved);
514  }
515  m_buffer = b;
516  m_reserved = _length;
517  }
518  }
519 } // ParaEngine
520 
StringBuilderT()
Creates a new builder with an empty buffer.
Definition: StringBuilder.hpp:221
void appendHex(uint8 i)
Appends the integer value, after converting it to a fm::string, in hexadecimal, to the content of the...
Definition: StringBuilder.hpp:388
int32 index(Char c) const
Retrieves the index of the first character within the content of the builder that is equivalent to th...
Definition: StringBuilder.hpp:429
different physics engine has different winding order.
Definition: EventBinding.h:32
int32 rindex(Char c) const
Retrieves the index of the last character within the content of the builder that is equivalent to the...
Definition: StringBuilder.hpp:443
void resize(size_t length)
resize the buffer
Definition: StringBuilder.hpp:247
void clear()
Clears the content of the builder.
Definition: StringBuilder.hpp:241
const Char * c_str() const
Converts the content of the builder to a character array.
Definition: StringBuilder.hpp:420
std::string string_type
The standard string object which correspond to the builder.
Definition: StringBuilder.h:35
void append(Char c)
Appends a character to the content of the builder.
Definition: StringBuilder.hpp:257
void remove(int32 start)
Removes a section of the content of the builder.
Definition: StringBuilder.hpp:399
void WriteAt(int nIndex, const TYPE &val)
this is useful for writing to a previous cached location.
Definition: StringBuilder.h:151
static bool IsEquivalent(float f1, float f2)
Returns whether two floating-point values are equivalent within a given tolerance.
Definition: ParaMath.h:417
void reserve(size_t length)
Reserves a given number of character slots.
Definition: StringBuilder.hpp:480
A NON-thread-safe, mutable sequence of characters(Binary is also possible).
Definition: StringBuilder.h:9
~StringBuilderT()
Deletes the builder.
Definition: StringBuilder.hpp:229
static int log2_ceil(unsigned int x)
this is a fast version of log2.
Definition: ParaMath.h:458
void appendLine(const Char *sz)
Appends a character array to the content of the builder.
Definition: StringBuilder.hpp:381