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 }

Generated on Thu Feb 14 16:58:36 2008 for FCollada by  doxygen 1.4.6-NO