- Main Page
- Modules
- Namespaces
- Classes
- Files
- Related Pages

- File List
- File Members

# FUtils/FUStringBuilder.hpp

    00001 /*
    00002     Copyright (C) 2005-2007 Feeling Software Inc.
    00003     Portions of the code are:
    00004     Copyright (C) 2005-2007 Sony Computer Entertainment America
    00005
    00006     MIT License: http://www.opensource.org/licenses/mit-license.php
    00007 */
    00008 /*
    00009     Based on the FS Import classes:
    00010     Copyright (C) 2005-2006 Feeling Software Inc
    00011     Copyright (C) 2005-2006 Autodesk Media Entertainment
    00012     MIT License: http://www.opensource.org/licenses/mit-license.php
    00013 */
    00014
    00015 #include <limits>
    00016
    00017 #ifdef WIN32
    00018 #include <float.h>
    00019 #endif
    00020
    00021 #ifdef WIN32
    00022 #define ecvt _ecvt
    00023 #endif // WIN32
    00024
    00025 #ifndef SAFE_DELETE_ARRAY
    00026 #define SAFE_DELETE_ARRAY(ptr) if (ptr != NULL) { delete [] ptr; ptr = NULL; }
    00027 #endif
    00028
    00029 template <class Char, class FloatType>
    00030 void FloatToString(FloatType f, Char* sz)
    00031 {
    00032     Char* buffer = sz + 1;
    00033     static const int digitCount = 6;
    00034     int decimal, sign;
    00035
    00036     // ecvt rounds the string for us: http://www.datafocus.com/docs/man3/ecvt.3.asp
    00037     char* end = ecvt(f, digitCount, &decimal, &sign);
    00038
    00039     if (sign != 0) (*buffer++) = '-';
    00040     int count = digitCount;
    00041     if (decimal > digitCount)
    00042     {
    00043         // We use the scientific notation: P.MeX
    00044         (*buffer++) = (*end++); // P is one character.
    00045         (*buffer++) = '.';
    00046
    00047         // Mantissa (cleaned for zeroes)
    00048         for (--count; count > 0; --count) if (end[count - 1] != '0') break;
    00049         for (int i = 0; i < count; ++i) (*buffer++) = (*end++);
    00050         if (buffer[-1] == '.') --buffer;
    00051
    00052         // Exponent
    00053         (*buffer++) = 'e';
    00054         uint32 exponent = decimal - 1; // X
    00055         if (exponent >= 10) (*buffer++) = (Char) ('0' + (exponent / 10));
    00056         (*buffer++) = (Char) ('0' + (exponent % 10));
    00057         (*buffer) = 0;
    00058         return;
    00059     }
    00060     else if (decimal > 0)
    00061     {
    00062         // Simple number: A.B
    00063         for (int i = 0; i < decimal; ++i) (*buffer++) = (*end++);
    00064         if (decimal < digitCount) (*buffer++) = '.';
    00065         count = digitCount - decimal;
    00066     }
    00067     else if (decimal < -digitCount)
    00068     {
    00069         // What case is this?
    00070         decimal = count = 0;
    00071     }
    00072     else if (decimal < 0 || (decimal == 0 && *end != '0'))
    00073     {
    00074         // Tiny number: 0.Me-X
    00075         (*buffer++) = '0'; (*buffer++) = '.';
    00076         for (int i = 0; i < -decimal; ++i) (*buffer++) = '0';
    00077         count = digitCount + decimal;
    00078     }
    00079     for (; count > 0; --count) if (end[count - 1] != '0') break;
    00080     for (int i = 0; i < count; ++i) (*buffer++) = (*end++);
    00081     if (decimal == 0 && count == 0) (*buffer++) = '0';
    00082     if (buffer[-1] == '.') --buffer;
    00083     (*buffer) = 0;
    00084 }
    00085
    00086 template <class Char>
    00087 FUStringBuilderT<Char>::FUStringBuilderT(const String& sz)
    00088 {
    00089     this->buffer = NULL;
    00090     this->size = 0;
    00091     this->reserved = 0;
    00092
    00093     reserve(sz.size() + 32);
    00094     append(sz.c_str());
    00095 }
    00096
    00097 template <class Char>
    00098 FUStringBuilderT<Char>::FUStringBuilderT(const Char* sz)
    00099 {
    00100     this->buffer = NULL;
    00101     this->size = 0;
    00102     this->reserved = 0;
    00103
    00104     size_t len = 0;
    00105     for (const Char* p = sz; *p != 0; ++p) ++len;
    00106     reserve(len + 32);
    00107     append(sz);
    00108 }
    00109
    00110 template <class Char>
    00111 FUStringBuilderT<Char>::FUStringBuilderT(Char ch, size_t count)
    00112 {
    00113     this->buffer = NULL;
    00114     this->size = 0;
    00115     this->reserved = 0;
    00116
    00117     reserve(count + 32);
    00118     for (size_t i = 0; i < count; ++i) buffer[size++] = ch;
    00119 }
    00120
    00121 template <class Char>
    00122 FUStringBuilderT<Char>::FUStringBuilderT(size_t reservation)
    00123 {
    00124     this->buffer = NULL;
    00125     this->size = 0;
    00126     this->reserved = 0;
    00127
    00128     reserve(reservation);
    00129 }
    00130
    00131 template <class Char>
    00132 FUStringBuilderT<Char>::FUStringBuilderT()
    00133 {
    00134     this->buffer = NULL;
    00135     this->size = 0;
    00136     this->reserved = 0;
    00137
    00138 #ifndef _DEBUG
    00139     reserve(32);
    00140 #endif
    00141 }
    00142
    00143 template <class Char>
    00144 FUStringBuilderT<Char>::~FUStringBuilderT()
    00145 {
    00146     reserve(0);
    00147 }
    00148
    00149 template <class Char>
    00150 void FUStringBuilderT<Char>::enlarge(size_t minimum)
    00151 {
    00152     reserve(max(reserved + minimum + 32, 2 * reserved + 32));
    00153 }
    00154
    00155 template <class Char>
    00156 void FUStringBuilderT<Char>::clear()
    00157 {
    00158     size = 0;
    00159 }
    00160
    00161 template <class Char>
    00162 void FUStringBuilderT<Char>::reserve(size_t _length)
    00163 {
    00164     FUAssert(size <= reserved,);
    00165     if (_length > reserved)
    00166     {
    00167         Char* b = new Char[_length];
    00168         memcpy(b, buffer, size * sizeof(Char));
    00169         SAFE_DELETE_ARRAY(buffer);
    00170         buffer = b;
    00171         reserved = _length;
    00172     }
    00173     else if (_length == 0)
    00174     {
    00175         SAFE_DELETE_ARRAY(buffer);
    00176         size = reserved = 0;
    00177     }
    00178     else if (_length < reserved)
    00179     {
    00180         size_t realSize = min(size, _length);
    00181         Char* b = new Char[_length];
    00182         memcpy(b, buffer, realSize * sizeof(Char));
    00183         SAFE_DELETE_ARRAY(buffer);
    00184         buffer = b;
    00185         reserved = _length;
    00186         size = realSize;
    00187     }
    00188 }
    00189
    00190 template <class Char>
    00191 void FUStringBuilderT<Char>::append(Char c)
    00192 {
    00193     if (size + 1 >= reserved) enlarge(2);
    00194
    00195     buffer[size++] = c;
    00196 }
    00197
    00198 template <class Char>
    00199 void FUStringBuilderT<Char>::append(const String& sz) { append(sz.c_str()); }
    00200 template <class Char>
    00201 void FUStringBuilderT<Char>::append(const Char* sz)
    00202 {
    00203     if (sz == NULL) return;
    00204
    00205     // This is optimized for SMALL strings.
    00206     for (; *sz != 0; ++sz)
    00207     {
    00208         if (size >= reserved) enlarge(64);
    00209         buffer[size++] = *sz;
    00210     }
    00211 }
    00212 template <class Char>
    00213 void FUStringBuilderT<Char>::append(const Char* sz, size_t len)
    00214 {
    00215     if (sz == NULL) return;
    00216
    00217     if (size + len >= reserved)
    00218     {
    00219         enlarge(max((size_t)64, size + len + 1));
    00220     }
    00221     memcpy(buffer + size, sz, len);
    00222     size += len;
    00223 }
    00224
    00225
    00226 template <class Char>
    00227 void FUStringBuilderT<Char>::append(const FUStringBuilderT& b)
    00228 {
    00229     if (size + b.size >= reserved) enlarge(64 + size + b.size - reserved);
    00230     memcpy(buffer + size, b.buffer, b.size * sizeof(Char));
    00231     size += b.size;
    00232 }
    00233
    00234 template <class Char>
    00235 void FUStringBuilderT<Char>::append(float f)
    00236 {
    00237 #ifdef WIN32
    00238     // use <float.h> _isnan method to detect the 1.#IND00 NaN.
    00239     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))
    00240 #else
    00241     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())
    00242 #endif
    00243     {
    00244         if (IsEquivalent(f, 0.0f, std::numeric_limits<float>::epsilon())) append((Char)'0');
    00245         else
    00246         {
    00247             Char sz[128];
    00248             FloatToString(f, sz);
    00249             append(sz + 1);
    00250         }
    00251     }
    00252     else if (f == std::numeric_limits<float>::infinity())
    00253     { append((Char)'I'); append((Char)'N'); append((Char)'F'); }
    00254     else if (f == -std::numeric_limits<float>::infinity())
    00255     { append((Char)'-'); append((Char)'I'); append((Char)'N'); append((Char)'F'); }
    00256     else
    00257     { append((Char)'N'); append((Char)'a'); append((Char)'N'); }
    00258 }
    00259
    00260 template <class Char>
    00261 void FUStringBuilderT<Char>::append(double f)
    00262 {
    00263 #ifdef WIN32
    00264     // use <float.h> _isnan method to detect the .#IND00 NaN.
    00265     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))
    00266 #else
    00267     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())
    00268 #endif
    00269     {
    00270         if (IsEquivalent(f, 0.0, std::numeric_limits<double>::epsilon())) append((Char)'0');
    00271         else
    00272         {
    00273             Char sz[128];
    00274             FloatToString(f, sz);
    00275             append(sz + 1);
    00276         }
    00277     }
    00278     else if (f == std::numeric_limits<double>::infinity())
    00279     { append((Char)'I'); append((Char)'N'); append((Char)'F'); }
    00280     else if (f == -std::numeric_limits<double>::infinity())
    00281     { append((Char)'-'); append((Char)'I'); append((Char)'N'); append((Char)'F'); }
    00282     else
    00283     { append((Char)'N'); append((Char)'a'); append((Char)'N'); }
    00284 }
    00285
    00286 template <class Char>
    00287 void FUStringBuilderT<Char>::append(const FMVector2& v)
    00288 {
    00289     if (!empty() && (back() != (Char) ' ' || back() != (Char) '\t' || back() != (Char) '\n' || back() != (Char) '\r'))
    00290     {
    00291         append((Char)' ');
    00292     }
    00293     append(v.x); append((Char)' '); append(v.y);
    00294 }
    00295
    00296 template <class Char>
    00297 void FUStringBuilderT<Char>::append(const FMVector3& v)
    00298 {
    00299     if (!empty() && (back() != (Char) ' ' || back() != (Char) '\t' || back() != (Char) '\n' || back() != (Char) '\r'))
    00300     {
    00301         append((Char)' ');
    00302     }
    00303     append(v.x); append((Char)' '); append(v.y); append((Char)' '); append(v.z);
    00304 }
    00305
    00306 template <class Char>
    00307 void FUStringBuilderT<Char>::append(const FMVector4& v)
    00308 {
    00309     if (!empty() && (back() != (Char) ' ' || back() != (Char) '\t' || back() != (Char) '\n' || back() != (Char) '\r'))
    00310     {
    00311         append((Char)' ');
    00312     }
    00313     append(v.x); append((Char)' '); append(v.y); append((Char)' '); append(v.z); append((Char)' '); append(v.w);
    00314 }
    00315
    00316 template <class Char>
    00317 void FUStringBuilderT<Char>::appendLine(const Char* sz)
    00318 {
    00319     append(sz);
    00320     append((Char)'\n');
    00321 }
    00322
    00323 template <class Char>
    00324 void FUStringBuilderT<Char>::appendHex(uint8 i)
    00325 {
    00326     uint8 top = (i & 0xF0) >> 4;
    00327     uint8 bot = i & 0xF;
    00328     if (top <= 0x9) append((Char) ('0' + top));
    00329     else append((Char) ('A' + (top - 0xA)));
    00330     if (bot <= 0x9) append((Char) ('0' + bot));
    00331     else append((Char) ('A' + (bot - 0xA)));
    00332 }
    00333
    00334 template <class Char>
    00335 void FUStringBuilderT<Char>::remove(int32 start)
    00336 {
    00337     if ((int32)size > start && start >= 0) size = start;
    00338 }
    00339
    00340 template <class Char>
    00341 void FUStringBuilderT<Char>::remove(int32 start, int32 end)
    00342 {
    00343     int32 diff = end - start;
    00344     if ((int32)size >= end && start >= 0 && diff > 0)
    00345     {
    00346         const Char* stop = buffer + size - diff;
    00347         for (Char* p = buffer + start; p != stop; ++p)
    00348         {
    00349             *p = *(p + diff);
    00350         }
    00351         size -= diff;
    00352     }
    00353 }
    00354
    00355 template <class Char>
    00356 const Char* FUStringBuilderT<Char>::ToCharPtr() const
    00357 {
    00358     FUStringBuilderT<Char>* ncThis = const_cast< FUStringBuilderT<Char>* >(this);
    00359     if (size + 1 > reserved) ncThis->enlarge(1);
    00360     ncThis->buffer[size] = 0;
    00361     return buffer;
    00362 }
    00363
    00364 template <class Char>
    00365 int32 FUStringBuilderT<Char>::index(Char c) const
    00366 {
    00367     if (buffer != NULL && size > 0)
    00368     {
    00369         const Char* end = buffer + size + 1;
    00370         for (const Char* p = buffer; p != end; ++p)
    00371         {
    00372             if (*p == c) return (int32)(p - buffer);
    00373         }
    00374     }
    00375     return -1;
    00376 }
    00377
    00378 template <class Char>
    00379 int32 FUStringBuilderT<Char>::rindex(Char c) const
    00380 {
    00381     if (buffer != NULL && size > 0)
    00382     {
    00383         for (const Char* p = buffer + size - 1; p != buffer; --p)
    00384         {
    00385             if (*p == c) return (int32)(p - buffer);
    00386         }
    00387     }
    00388     return -1;
    00389 }