/* Copyright (C) 2005-2007 Feeling Software Inc. Portions of the code are: Copyright (C) 2005-2007 Sony Computer Entertainment America MIT License: http://www.opensource.org/licenses/mit-license.php */ /* Based on the FS Import classes: Copyright (C) 2005-2006 Feeling Software Inc Copyright (C) 2005-2006 Autodesk Media Entertainment MIT License: http://www.opensource.org/licenses/mit-license.php */ #ifndef _FU_FUSTRINGBUILDER_HPP_ #define _FU_FUSTRINGBUILDER_HPP_ #include #include #include #include #ifdef WIN32 #include #endif #ifndef SAFE_DELETE_ARRAY #define SAFE_DELETE_ARRAY(ptr) { delete [] ptr; ptr = nullptr; } #endif #ifdef UNICODE std::wstring ToXmlDouble(double value) { std::wstringstream str; str.precision(5); str << (value < -1e6f || value > 1e6f ? std::scientific : std::fixed) << value; // This removes exponent and trailing zeroes, and the exponent +. std::wregex e(L"(-*[0-9]*)((\\.[0-9]*[1-9])0*|(\\.0*))(e*-*)\\+*0*([0-9]*)"); return std::regex_replace(str.str(), e, L"$1$3$5$6"); } #else std::string ToXmlDouble(double value) { std::ostringstream str; str.precision(5); str << (value < -1e6f || value > 1e6f ? std::scientific : std::fixed) << value; // This removes exponent and trailing zeroes, and the exponent +. std::regex e("(-*[0-9]*)((\\.[0-9]*[1-9])0*|(\\.0*))(e*-*)\\+*0*([0-9]*)"); return std::regex_replace(str.str(), e, "$1$3$5$6"); } #endif template FUStringBuilderT::FUStringBuilderT(const String& sz) { this->buffer = NULL; this->size = 0; this->reserved = 0; reserve(sz.size() + 32); append(sz.c_str()); } template FUStringBuilderT::FUStringBuilderT(const Char* sz) { this->buffer = NULL; this->size = 0; this->reserved = 0; size_t len = 0; for (const Char* p = sz; *p != 0; ++p) ++len; reserve(len + 32); append(sz); } template FUStringBuilderT::FUStringBuilderT(Char ch, size_t count) { this->buffer = NULL; this->size = 0; this->reserved = 0; reserve(count + 32); for (size_t i = 0; i < count; ++i) buffer[size++] = ch; } template FUStringBuilderT::FUStringBuilderT(size_t reservation) { this->buffer = NULL; this->size = 0; this->reserved = 0; reserve(reservation); } template FUStringBuilderT::FUStringBuilderT() { this->buffer = NULL; this->size = 0; this->reserved = 0; #ifndef _DEBUG reserve(32); #endif } template FUStringBuilderT::~FUStringBuilderT() { reserve(0); } template void FUStringBuilderT::enlarge(size_t minimum) { reserve(max(reserved + minimum + 32, 2 * reserved + 32)); } template void FUStringBuilderT::clear() { size = 0; } template void FUStringBuilderT::reserve(size_t _length) { FUAssert(size <= reserved,); if (_length > reserved) { Char* b = new Char[_length]; memcpy(b, buffer, size * sizeof(Char)); SAFE_DELETE_ARRAY(buffer); buffer = b; reserved = _length; } else if (_length == 0) { SAFE_DELETE_ARRAY(buffer); size = reserved = 0; } else if (_length < reserved) { size_t realSize = min(size, _length); Char* b = new Char[_length]; memcpy(b, buffer, realSize * sizeof(Char)); SAFE_DELETE_ARRAY(buffer); buffer = b; reserved = _length; size = realSize; } } template void FUStringBuilderT::append(Char c) { if (size + 1 >= reserved) enlarge(2); buffer[size++] = c; } template void FUStringBuilderT::append(const String& sz) { append(sz.c_str()); } template void FUStringBuilderT::append(const Char* sz) { if (sz == NULL) return; // This is optimized for SMALL strings. for (; *sz != 0; ++sz) { if (size >= reserved) enlarge(64); buffer[size++] = *sz; } } template void FUStringBuilderT::append(const Char* sz, size_t len) { if (sz == NULL) return; if (size + len >= reserved) { enlarge(max((size_t)64, size + len + 1)); } memcpy(buffer + size, sz, len); size += len; } template void FUStringBuilderT::append(const FUStringBuilderT& b) { if (size + b.size >= reserved) enlarge(64 + size + b.size - reserved); memcpy(buffer + size, b.buffer, b.size * sizeof(Char)); size += b.size; } template void FUStringBuilderT::append(float f) { #ifdef WIN32 // use _isnan method to detect the 1.#IND00 NaN. if (f != std::numeric_limits::infinity() && f != -std::numeric_limits::infinity() && f != std::numeric_limits::quiet_NaN() && f != std::numeric_limits::signaling_NaN() && !_isnan((double)f)) #else if (f != std::numeric_limits::infinity() && f != -std::numeric_limits::infinity() && f != std::numeric_limits::quiet_NaN() && f != std::numeric_limits::signaling_NaN()) #endif { if (IsEquivalent(f, 0.0f, std::numeric_limits::epsilon())) append((Char)'0'); else for (Char c : ToXmlDouble(f)) append(c); } else if (f == std::numeric_limits::infinity()) { append((Char)'I'); append((Char)'N'); append((Char)'F'); } else if (f == -std::numeric_limits::infinity()) { append((Char)'-'); append((Char)'I'); append((Char)'N'); append((Char)'F'); } else { append((Char)'N'); append((Char)'a'); append((Char)'N'); } } template void FUStringBuilderT::append(double f) { #ifdef WIN32 // use _isnan method to detect the .#IND00 NaN. if (f != std::numeric_limits::infinity() && f != -std::numeric_limits::infinity() && f != std::numeric_limits::quiet_NaN() && f != std::numeric_limits::signaling_NaN() && !_isnan(f)) #else if (f != std::numeric_limits::infinity() && f != -std::numeric_limits::infinity() && f != std::numeric_limits::quiet_NaN() && f != std::numeric_limits::signaling_NaN()) #endif { if (IsEquivalent(f, 0.0, std::numeric_limits::epsilon())) append((Char)'0'); else for (Char c : ToXmlDouble(f)) append(c); } else if (f == std::numeric_limits::infinity()) { append((Char)'I'); append((Char)'N'); append((Char)'F'); } else if (f == -std::numeric_limits::infinity()) { append((Char)'-'); append((Char)'I'); append((Char)'N'); append((Char)'F'); } else { append((Char)'N'); append((Char)'a'); append((Char)'N'); } } template void FUStringBuilderT::append(const FMVector2& v) { if (!empty() && (back() != (Char) ' ' || back() != (Char) '\t' || back() != (Char) '\n' || back() != (Char) '\r')) { append((Char)' '); } append(v.x); append((Char)' '); append(v.y); } template void FUStringBuilderT::append(const FMVector3& v) { if (!empty() && (back() != (Char) ' ' || back() != (Char) '\t' || back() != (Char) '\n' || back() != (Char) '\r')) { append((Char)' '); } append(v.x); append((Char)' '); append(v.y); append((Char)' '); append(v.z); } template void FUStringBuilderT::append(const FMVector4& v) { if (!empty() && (back() != (Char) ' ' || back() != (Char) '\t' || back() != (Char) '\n' || back() != (Char) '\r')) { append((Char)' '); } append(v.x); append((Char)' '); append(v.y); append((Char)' '); append(v.z); append((Char)' '); append(v.w); } template void FUStringBuilderT::appendLine(const Char* sz) { append(sz); append((Char)'\n'); } template void FUStringBuilderT::appendHex(uint8 i) { uint8 top = (i & 0xF0) >> 4; uint8 bot = i & 0xF; if (top <= 0x9) append((Char) ('0' + top)); else append((Char) ('A' + (top - 0xA))); if (bot <= 0x9) append((Char) ('0' + bot)); else append((Char) ('A' + (bot - 0xA))); } template void FUStringBuilderT::remove(int32 start) { if ((int32)size > start && start >= 0) size = start; } template void FUStringBuilderT::remove(int32 start, int32 end) { int32 diff = end - start; if ((int32)size >= end && start >= 0 && diff > 0) { const Char* stop = buffer + size - diff; for (Char* p = buffer + start; p != stop; ++p) { *p = *(p + diff); } size -= diff; } } template const Char* FUStringBuilderT::ToCharPtr() const { FUStringBuilderT* ncThis = const_cast< FUStringBuilderT* >(this); if (size + 1 > reserved) ncThis->enlarge(1); ncThis->buffer[size] = 0; return buffer; } template int32 FUStringBuilderT::index(Char c) const { if (buffer != NULL && size > 0) { const Char* end = buffer + size + 1; for (const Char* p = buffer; p != end; ++p) { if (*p == c) return (int32)(p - buffer); } } return -1; } template int32 FUStringBuilderT::rindex(Char c) const { if (buffer != NULL && size > 0) { for (const Char* p = buffer + size - 1; p != buffer; --p) { if (*p == c) return (int32)(p - buffer); } } return -1; } #endif // _FU_FUSTRINGBUILDER_HPP_