From 2a7829bce7718b0029c5307647595aaae7f509d5 Mon Sep 17 00:00:00 2001 From: JustinAJ Date: Sun, 1 Jun 2014 18:10:18 -0400 Subject: [PATCH] Completed Jupiter::String. --- Jupiter/String.h | 417 +++++++++++++++++++++++++++++++++++++ Jupiter/String_Imp.h | 484 +++++++++++++++++++++++++++++++++++++++++++ Release/Jupiter.lib | Bin 193990 -> 194266 bytes 3 files changed, 901 insertions(+) create mode 100644 Jupiter/String.h create mode 100644 Jupiter/String_Imp.h diff --git a/Jupiter/String.h b/Jupiter/String.h new file mode 100644 index 0000000..10d900e --- /dev/null +++ b/Jupiter/String.h @@ -0,0 +1,417 @@ +/** + * Copyright (C) 2013-2014 Justin James. + * + * This license must be preserved. + * Any applications, libraries, or code which make any use of any + * component of this program must not be commercial, unless explicit + * permission is granted from the original author. The use of this + * program for non-profit purposes is permitted. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * In the event that this license restricts you from making desired use of this program, contact the original author. + * Written by Justin James + */ + +#if !defined _STRING_H_HEADER +#define _STRING_H_HEADER + +/** + * @file String.h + * @brief Defines the base String_Base, as well as a series of String types. + * Note: Functions which take "case" or "wildcards" into consideration will only function + * for types char and wchar_t; inputs with other types will simply return false. + */ + +#include "Shift_String.h" + +namespace Jupiter +{ + + /** + * @brief Provides a minimal String implementation (i.e: no extra variables). + * + * @param T Element type which the String will store. Defaults to char. + */ + template class String_Strict : public Shift_String_Type + { + public: + + /** + * @brief Returns a C-Style string representation of the String. + * + * @return C-Style string representation of the String. + */ + const T *c_str() const; + + /** + * @brief Sets the String's contents based on the format string and input variables. + * Note: Format specifiers similar to printf. Returns 0 for any type other than char and wchar_t. + * + * @param format Format that the string is compared against. + * @param args Inputs to match the format specifiers. + * @return Number of characters written. + */ + size_t vformat(const T *format, va_list args); + + /** + * @brief Appends to a String's contents based on the format string and input variables. + * Note: Format specifiers similar to printf. Returns 0 for any type other than char and wchar_t. + * + * @param format Format that the string is compared against. + * @param args Inputs to match the format specifiers. + * @return Number of characters written. + */ + size_t avformat(const T *format, va_list args); + + /** + * @brief Sets the String's contents based on the format string and input variables. + * Note: Format specifiers similar to printf. Returns 0 for any type other than char and wchar_t. + * + * @param format Format that the string is compared against. + * @param ... Inputs to match the format specifiers. + * @return String containing the new format. + */ + static String_Strict Format(const T *format, ...); + + /** + * @brief Creates a partial copy of the string. + * + * @param pos Position in the string to start copying from. + * @return String containing a partial copy of the original string. + */ + String_Strict substring(size_t pos) const; + + /** + * @brief Creates a partial copy of the string. + * + * @param pos Position in the string to start copying from. + * @param length Number of characters to copy. + * @return String containing a partial copy of the original string. + */ + String_Strict substring(size_t pos, size_t length) const; + + /** + * @brief Creates a partial copy of the string. + * + * @param in String to get a partial copy of. + * @param pos Position in the string to start copying from. + * @return String containing a partial copy of the original string. + */ + static String_Strict substring(const Jupiter::String_Type &in, size_t pos); + static String_Strict substring(const T *in, size_t pos); + + /** + * @brief Creates a partial copy of the string. + * + * @param in String to get a partial copy of. + * @param pos Position in the string to start copying from. + * @param length Number of characters to copy. + * @return String containing a partial copy of the original string. + */ + static String_Strict substring(const Jupiter::String_Type &in, size_t pos, size_t length); + static String_Strict substring(const T *in, size_t pos, size_t length); + + /** + * @brief Creates a partial copy of the string, based on a set of tokens. + * + * @param pos Position of word in the string to start copying from. + * @param whitespace A string of tokens used to deliminate words. + * @return String containing a partial copy of the original string. + */ + String_Strict getWord(size_t pos, const T *whitespace) const; + + /** + * @brief Creates a partial copy of an input string, based on a set of tokens. + * + * @param in String to get a partial copy of. + * @param pos Position of word in the string to start copying from. + * @param whitespace A string of tokens used to deliminate words. + * @return String containing a partial copy of the original string. + */ + static String_Strict getWord(const Jupiter::String_Type &in, size_t pos, const T *whitespace); + + /** + * @brief Creates a partial copy of an input string, based on a set of tokens. + * + * @param in C-Style string to get a partial copy of. + * @param pos Position of word in the string to start copying from. + * @param whitespace A string of tokens used to deliminate words. + * @return String containing a partial copy of the original string. + */ + static String_Strict getWord(const T *in, size_t pos, const T *whitespace); + + /** + * @brief Creates a partial copy of the string, based on a set of tokens. + * + * @param pos Position in the string to start copying from. + * @param whitespace A string of tokens used to deliminate words. + * @return String containing a partial copy of the original string. + */ + String_Strict gotoWord(size_t pos, const T *whitespace) const; + + /** + * @brief Creates a partial copy of the string, based on a set of tokens. + * + * @param in String to get a partial copy of. + * @param pos Position in the string to start copying from. + * @param whitespace A string of tokens used to deliminate words. + * @return String containing a partial copy of the original string. + */ + static String_Strict gotoWord(const Jupiter::String_Type &in, size_t pos, const T *whitespace); + + /** Assignment Operators */ + inline String_Strict &operator=(const String_Strict &right) { this->set(right); return *this; }; + inline String_Strict &operator=(const String_Type &right) { this->set(right); return *this; }; + inline String_Strict &operator=(const std::basic_string &right) { this->set(right); return *this; }; + inline String_Strict &operator=(const T *right) { this->set(right); return *this; }; + inline String_Strict &operator=(const T right) { this->set(right); return *this; }; + + static const Jupiter::String_Strict empty; /** Empty instantation of String_Strict */ + + /** Default Constructor */ + String_Strict(); + + /** + * @brief Size hint constructor. + * Note: For the String_Strict base class, this is only truly useful internally. + * + * @param size Minimum number of elements the string must be able to hold. + */ + String_Strict(size_t size); + + /** Move Constructor */ + String_Strict(String_Strict &&source); + + /** Copy Constructors */ + String_Strict(const String_Strict &in) : String_Strict((String_Type &)in) {} + String_Strict(const String_Type &in); + String_Strict(const std::basic_string &in); + String_Strict(const T *in); + + protected: + + /** Dummy constructor to prevent string initialization */ + String_Strict(Jupiter::String_Constructor_Base &) {}; + }; + + /** + * @brief Provides a "loose" String implementation that's more optimized for repeated concatenations. + * Note: The underlying string will always have a size which is a power of 2, but no fewer than 8 elements. + * + * @param T Element type which the String will store. Defaults to char. + */ + template class String_Loose : public Shift_String_Type + { + public: + + /** + * @brief Returns a C-Style string representation of the String. + * + * @return C-Style string representation of the String. + */ + const T *c_str() const; + + /** + * @brief Sets the String's contents based on the format string and input variables. + * Note: Format specifiers similar to printf. Returns 0 for any type other than char and wchar_t. + * + * @param format Format that the string is compared against. + * @param args Inputs to match the format specifiers. + * @return Number of characters written. + */ + size_t vformat(const T *format, va_list args); + + /** + * @brief Appends to a String's contents based on the format string and input variables. + * Note: Format specifiers similar to printf. Returns 0 for any type other than char and wchar_t. + * + * @param format Format that the string is compared against. + * @param args Inputs to match the format specifiers. + * @return Number of characters written. + */ + size_t avformat(const T *format, va_list args); + + /** + * @brief Sets the String's contents based on the format string and input variables. + * Note: Format specifiers similar to printf. Returns 0 for any type other than char and wchar_t. + * + * @param format Format that the string is compared against. + * @param ... Inputs to match the format specifiers. + * @return String containing the new format. + */ + static String_Loose Format(const T *format, ...); + + /** + * @brief Creates a partial copy of the string. + * + * @param pos Position in the string to start copying from. + * @return String containing a partial copy of the original string. + */ + String_Loose substring(size_t pos) const; + + /** + * @brief Creates a partial copy of the string. + * + * @param pos Position in the string to start copying from. + * @param length Number of characters to copy. + * @return String containing a partial copy of the original string. + */ + String_Loose substring(size_t pos, size_t length) const; + + /** + * @brief Creates a partial copy of the string. + * + * @param in String to get a partial copy of. + * @param pos Position in the string to start copying from. + * @return String containing a partial copy of the original string. + */ + static String_Loose substring(const Jupiter::String_Type &in, size_t pos); + static String_Loose substring(const T *in, size_t pos); + + /** + * @brief Creates a partial copy of the string. + * + * @param in String to get a partial copy of. + * @param pos Position in the string to start copying from. + * @param length Number of characters to copy. + * @return String containing a partial copy of the original string. + */ + static String_Loose substring(const Jupiter::String_Type &in, size_t pos, size_t length); + static String_Loose substring(const T *in, size_t pos, size_t length); + + /** + * @brief Creates a partial copy of the string, based on a set of tokens. + * + * @param pos Position in the string to start copying from. + * @param whitespace A string of tokens used to deliminate words. + * @return String containing a partial copy of the original string. + */ + String_Loose getWord(size_t pos, const T *whitespace) const; + + /** + * @brief Creates a partial copy of an input string, based on a set of tokens. + * Useful when the input string's type isn't known. + * + * @param in String to get a partial copy of. + * @param pos Position of word in the string to start copying from. + * @param whitespace A string of tokens used to deliminate words. + * @return String containing a partial copy of the original string. + */ + static String_Loose getWord(const Jupiter::String_Type &in, size_t pos, const T *whitespace); + + /** + * @brief Creates a partial copy of an input string, based on a set of tokens. + * Useful when the input string's type isn't known. + * + * @param in C-Style string to get a partial copy of. + * @param pos Position of word in the string to start copying from. + * @param whitespace A string of tokens used to deliminate words. + * @return String containing a partial copy of the original string. + */ + static String_Loose getWord(const T *in, size_t pos, const T *whitespace); + + /** + * @brief Creates a partial copy of the string, based on a set of tokens. + * + * @param pos Position in the string to start copying from. + * @param whitespace A string of tokens used to deliminate words. + * @return String containing a partial copy of the original string. + */ + String_Loose gotoWord(size_t pos, const T *whitespace) const; + + /** + * @brief Creates a partial copy of the string, based on a set of tokens. + * + * @param in String to get a partial copy of. + * @param pos Position in the string to start copying from. + * @param whitespace A string of tokens used to deliminate words. + * @return String containing a partial copy of the original string. + */ + static String_Loose gotoWord(const Jupiter::String_Type &in, size_t pos, const T *whitespace); + + /** Default constructor */ + String_Loose(); + + /** + * @brief Size hint constructor. + * + * @param size Minimum number of elements the string must be able to hold. + */ + String_Loose(size_t size); + + /** Move Constructor */ + String_Loose(String_Loose &&source); + + /** Copy Constructors */ + String_Loose(const String_Loose &in); + String_Loose(const String_Type &in); + String_Loose(const std::basic_string &in); + String_Loose(const T *in); + + static const Jupiter::String_Loose empty; /** Empty instantation of String_Loose */ + static const size_t start_size = 8; /** Starting size for loose Strings. */ + + /** Assignment Operators */ + inline String_Loose &operator=(const String_Loose &right) { this->set(right); return *this; }; + inline String_Loose &operator=(const String_Type &right) { this->set(right); return *this; }; + inline String_Loose &operator=(const std::basic_string &right) { this->set(right); return *this; }; + inline String_Loose &operator=(const T *right) { this->set(right); return *this; }; + inline String_Loose &operator=(const T right) { this->set(right); return *this; }; + + protected: + + /** + * @brief Sets the internal buffer to be at least large enough to old a specified number of elements. + * Note: This does nothing if len is less than the string's current length. + * + * @param len Minimum number of elements the string buffer must be able to hold. + * @return True if a new buffer was allocated, false otherwise. + */ + virtual bool setBufferSize(size_t len); + + /** + * @brief Empties the string, and sets the internal buffer to be at least large enough to old a specified number of elements. + * Note: This does nothing if len is less than the string's current length. + * + * @param len Minimum number of elements the string buffer must be able to hold. + * @return True if a new buffer was allocated, false otherwise. + */ + virtual bool setBufferSizeNoCopy(size_t len); + + /** Dummy constructor to prevent string initialization */ + String_Loose(Jupiter::String_Constructor_Base &) {}; + + size_t strSize; /** Size of underlying string buffer */ + }; + + /** Definition of a Loose String. */ + typedef String_Loose StringL; + + /** Definition of a Loose Wide String */ + typedef String_Loose WStringL; + + /** Definition of a Strict String. */ + typedef String_Strict StringS; + + /** Definition of a Strict Wide String */ + typedef String_Strict WStringS; + + /** Definition of a String. */ + typedef StringL String; + + /** Definition of a Wide String */ + typedef WStringL WString; + + /** Empty String constants */ + static const Jupiter::StringS &emptyStringS = Jupiter::StringS::empty; + static const Jupiter::StringL &emptyStringL = Jupiter::StringL::empty; + //static const Jupiter::StringType &emptyString = emptyStringS; +} + +/** Implementation for String_Strict and String_Loose. Very scary. */ +#include "String_Imp.h" + +#endif // _STRING_H_HEADER \ No newline at end of file diff --git a/Jupiter/String_Imp.h b/Jupiter/String_Imp.h new file mode 100644 index 0000000..23299d4 --- /dev/null +++ b/Jupiter/String_Imp.h @@ -0,0 +1,484 @@ +/** + * Copyright (C) 2013-2014 Justin James. + * + * This license must be preserved. + * Any applications, libraries, or code which make any use of any + * component of this program must not be commercial, unless explicit + * permission is granted from the original author. The use of this + * program for non-profit purposes is permitted. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * In the event that this license restricts you from making desired use of this program, contact the original author. + * Written by Justin James + */ + +#if !defined _STRING_IMP_H_HEADER +#define _STRING_IMP_H_HEADER + +/** +* @file String_Imp.h +* @brief Provides the implementations for String_Strict and String_Loose. +* Note: Modification of this file is not supported in any way. +*/ + +#include "String.h" + +#if !defined va_copy + +#if defined __INTEL_COMPILER +#pragma message("Warning: va_copy not properly defined. Assuming common implementation.") +#define va_copy(dst, src) ((void)((dst) = (src))) +#else +#error "va_copy not defined." +#endif // __INTEL_COMPILER + +#endif // va_copy + +/** +* IMPLEMENTATION: +* String_Strict +*/ + +template Jupiter::String_Strict::String_Strict() : Jupiter::String_Strict::String_Strict(size_t(0)) +{ +} + +template Jupiter::String_Strict::String_Strict(size_t len) +{ + Jupiter::Shift_String_Type::base = new T[len]; + Jupiter::String_Type::str = Jupiter::Shift_String_Type::base; + Jupiter::String_Type::length = 0; +} + +template Jupiter::String_Strict::String_Strict(Jupiter::String_Strict &&source) : Jupiter::Shift_String_Type(std::move(source)) +{ +} + +template Jupiter::String_Strict::String_Strict(const Jupiter::String_Type &in) : Jupiter::String_Strict::String_Strict(in.size()) +{ + while (Jupiter::String_Type::length < in.size()) + { + Jupiter::String_Type::str[Jupiter::String_Type::length] = in.get(Jupiter::String_Type::length); + Jupiter::String_Type::length++; + } +} + +template Jupiter::String_Strict::String_Strict(const std::basic_string &in) : Jupiter::String_Strict::String_Strict(in.size()) +{ + while (Jupiter::String_Type::length < in.size()) + { + Jupiter::String_Type::str[Jupiter::String_Type::length] = in.at(Jupiter::String_Type::length); + Jupiter::String_Type::length++; + } +} + +template Jupiter::String_Strict::String_Strict(const T *in) +{ + if (in == nullptr) Jupiter::String_Type::length = 0; + else Jupiter::String_Type::length = Jupiter::strlen(in); + + Jupiter::Shift_String_Type::base = new T[Jupiter::String_Type::length]; + Jupiter::String_Type::str = Jupiter::Shift_String_Type::base; + for (size_t index = 0; *in != 0; index++, in++) Jupiter::String_Type::str[index] = *in; +} + +template const T *Jupiter::String_Strict::c_str() const +{ + static T *buff = new T[1]; + delete[] buff; + + buff = new T[Jupiter::String_Type::length + 1]; + size_t index; + for (index = 0; index < Jupiter::String_Type::length && Jupiter::String_Type::str[index] != 0; index++) buff[index] = Jupiter::String_Type::str[index]; + buff[index] = 0; + + return buff; +} + +// vformat() + +template<> size_t inline Jupiter::String_Strict::vformat(const char *format, va_list args) +{ + int minLen; + va_list sargs; + va_copy(sargs, args); + minLen = vsnprintf(nullptr, 0, format, sargs); + va_end(sargs); + if (minLen < 0) return 0; // We simply can not work with this. + + this->setBufferSizeNoCopy(minLen + 1); // vsnprintf REQUIRES space for an additional null character. + minLen = vsnprintf(Jupiter::String_Type::str, Jupiter::String_Type::length + 1, format, args); + if (minLen < 0) return 0; + return Jupiter::String_Type::length = minLen; +} + +template<> size_t inline Jupiter::String_Strict::vformat(const wchar_t *format, va_list args) +{ + int minLen; + va_list sargs; + va_copy(sargs, args); + minLen = vswprintf(nullptr, 0, format, sargs); + va_end(sargs); + if (minLen < 0) return 0; // We simply can not work with this. + + this->setBufferSizeNoCopy(minLen + 1); // vsnprintf REQUIRES space for an additional null character. + minLen = vswprintf(Jupiter::String_Type::str, Jupiter::String_Type::length + 1, format, args); + if (minLen < 0) return 0; + return Jupiter::String_Type::length = minLen; +} + +template size_t Jupiter::String_Strict::vformat(const T *format, va_list args) +{ + return 0; +} + +// avformat() + +template<> size_t inline Jupiter::String_Strict::avformat(const char *format, va_list args) +{ + int minLen; + va_list sargs; + va_copy(sargs, args); + minLen = vsnprintf(nullptr, 0, format, sargs); + va_end(sargs); + if (minLen < 0) return 0; // We simply can not work with this. + + this->setBufferSize(Jupiter::String_Type::length + minLen + 1); // vsnprintf REQUIRES space for an additional null character. + minLen = vsnprintf(Jupiter::String_Type::str + Jupiter::String_Type::length + 1, minLen, format, args); + if (minLen <= 0) return 0; + Jupiter::String_Type::length += minLen; + return minLen; +} + +template<> size_t inline Jupiter::String_Strict::avformat(const wchar_t *format, va_list args) +{ + int minLen; + va_list sargs; + va_copy(sargs, args); + minLen = vswprintf(nullptr, 0, format, sargs); + va_end(sargs); + if (minLen < 0) return 0; // We simply can not work with this. + this->setBufferSize(minLen + Jupiter::String_Type::length + 1); // vsnprintf REQUIRES space for an additional null character. + + minLen = vswprintf(Jupiter::String_Type::str + Jupiter::String_Type::length + 1, minLen, format, args); + if (minLen <= 0) return 0; + Jupiter::String_Type::length += minLen; + return minLen; +} + +template size_t Jupiter::String_Strict::avformat(const T *format, va_list args) +{ + return 0; +} + +template Jupiter::String_Strict Jupiter::String_Strict::Format(const T *format, ...) +{ + String_Strict r; + va_list args; + va_start(args, format); + r.vformat(format, args); + va_end(args); + return r; +} + +template Jupiter::String_Strict Jupiter::String_Strict::substring(size_t pos) const +{ + return Jupiter::String_Strict::substring(*this, pos); +} + +template Jupiter::String_Strict Jupiter::String_Strict::substring(size_t pos, size_t len) const +{ + return Jupiter::String_Strict::substring(*this, pos, len); +} + +template Jupiter::String_Strict Jupiter::String_Strict::substring(const Jupiter::String_Type &in, size_t pos) +{ + return Jupiter::String_Type::substring(in, pos); +} + +template Jupiter::String_Strict Jupiter::String_Strict::substring(const T *in, size_t pos) +{ + return Jupiter::String_Type::substring(in, pos); +} + +template Jupiter::String_Strict Jupiter::String_Strict::substring(const Jupiter::String_Type &in, size_t pos, size_t len) +{ + return Jupiter::String_Type::substring(in, pos, len); +} + +template Jupiter::String_Strict Jupiter::String_Strict::substring(const T *in, size_t pos, size_t len) +{ + return Jupiter::String_Type::substring(in, pos, len); +} + +template Jupiter::String_Strict Jupiter::String_Strict::getWord(size_t pos, const T *whitespace) const +{ + return Jupiter::String_Strict::getWord(*this, pos, whitespace); +} + +template Jupiter::String_Strict Jupiter::String_Strict::getWord(const Jupiter::String_Type &in, size_t pos, const T *whitespace) +{ + return Jupiter::String_Type::getWord(in, pos, whitespace); +} + +template Jupiter::String_Strict Jupiter::String_Strict::getWord(const T *in, size_t pos, const T *whitespace) +{ + return Jupiter::String_Type::getWord(in, pos, whitespace); +} + +template Jupiter::String_Strict Jupiter::String_Strict::gotoWord(size_t pos, const T *whitespace) const +{ + return Jupiter::String_Strict::gotoWord(*this, pos, whitespace); +} + +template Jupiter::String_Strict Jupiter::String_Strict::gotoWord(const Jupiter::String_Type &in, size_t pos, const T *whitespace) +{ + return Jupiter::String_Type::gotoWord(in, pos, whitespace); +} + +template const Jupiter::String_Strict Jupiter::String_Strict::empty = Jupiter::String_Strict(); + +/** +* IMPLEMENTATION: +* String_Loose +*/ + +template Jupiter::String_Loose::String_Loose() : Jupiter::String_Loose::String_Loose(Jupiter::String_Loose::start_size) +{ +} + +template Jupiter::String_Loose::String_Loose(Jupiter::String_Loose &&source) : Jupiter::Shift_String_Type(std::move(source)) +{ + Jupiter::String_Loose::strSize = source.strSize; + source.strSize = 0; +} + +template Jupiter::String_Loose::String_Loose(size_t len) +{ + if (len > Jupiter::String_Loose::start_size) Jupiter::String_Loose::strSize = len; + else Jupiter::String_Loose::strSize = Jupiter::String_Loose::start_size; + + Jupiter::Shift_String_Type::base = new T[Jupiter::String_Loose::strSize]; + Jupiter::String_Type::str = Jupiter::Shift_String_Type::base; + Jupiter::String_Type::length = 0; +} + +template Jupiter::String_Loose::String_Loose(const Jupiter::String_Loose &in) +{ + Jupiter::String_Loose::strSize = in.strSize; + Jupiter::Shift_String_Type::base = new T[Jupiter::String_Loose::strSize]; + Jupiter::String_Type::str = Jupiter::Shift_String_Type::base; + for (Jupiter::String_Type::length = 0; Jupiter::String_Type::length != in.length; Jupiter::String_Type::length++) + Jupiter::String_Type::str[Jupiter::String_Type::length] = in.get(Jupiter::String_Type::length); +} + +template Jupiter::String_Loose::String_Loose(const Jupiter::String_Type &in) : Jupiter::String_Loose::String_Loose(in.size()) +{ + while (Jupiter::String_Type::length < in.size()) + { + Jupiter::String_Type::str[Jupiter::String_Type::length] = in.get(Jupiter::String_Type::length); + Jupiter::String_Type::length++; + } +} + +template Jupiter::String_Loose::String_Loose(const std::basic_string &in) : Jupiter::String_Loose::String_Loose(in.size()) +{ + while (Jupiter::String_Type::length < in.size()) + { + Jupiter::String_Type::str[Jupiter::String_Type::length] = in.at(Jupiter::String_Type::length); + Jupiter::String_Type::length++; + } +} + +template Jupiter::String_Loose::String_Loose(const T *in) +{ + if (in == nullptr) + { + Jupiter::String_Loose::strSize = Jupiter::String_Loose::start_size; + Jupiter::Shift_String_Type::base = new T[Jupiter::String_Loose::strSize]; + Jupiter::String_Type::str = Jupiter::Shift_String_Type::base; + Jupiter::String_Type::length = 0; + } + else + { + Jupiter::String_Type::length = Jupiter::strlen(in); + + Jupiter::String_Loose::strSize = getPowerTwo32(Jupiter::String_Type::length); + if (Jupiter::String_Loose::strSize < Jupiter::String_Loose::start_size) Jupiter::String_Loose::strSize = Jupiter::String_Loose::start_size; + + Jupiter::Shift_String_Type::base = new T[Jupiter::String_Loose::strSize]; + Jupiter::String_Type::str = Jupiter::Shift_String_Type::base; + for (Jupiter::String_Type::length = 0; *in != 0; Jupiter::String_Type::length++, in++) Jupiter::String_Type::str[Jupiter::String_Type::length] = *in; + } +} + +template bool Jupiter::String_Loose::setBufferSize(size_t len) +{ + return Jupiter::Shift_String_Type::setBufferSize(Jupiter::String_Loose::strSize = getPowerTwo32(len)); +} + +template bool Jupiter::String_Loose::setBufferSizeNoCopy(size_t len) +{ + return Jupiter::Shift_String_Type::setBufferSizeNoCopy(Jupiter::String_Loose::strSize = getPowerTwo32(len)); +} + +template const T *Jupiter::String_Loose::c_str() const +{ + static T *buff = new T[1]; + delete[] buff; + + buff = new T[Jupiter::String_Type::length + 1]; + size_t index; + for (index = 0; index < Jupiter::String_Type::length && Jupiter::String_Type::str[index] != 0; index++) buff[index] = Jupiter::String_Type::str[index]; + buff[index] = 0; + + return buff; +} + +// vformat() + +template<> size_t inline Jupiter::String_Loose::vformat(const char *format, va_list args) +{ + int minLen; + va_list sargs; + va_copy(sargs, args); + minLen = vsnprintf(nullptr, 0, format, sargs); + va_end(sargs); + if (minLen < 0) return 0; // We simply can not work with this. + + this->setBufferSizeNoCopy(minLen + 1); // vsnprintf REQUIRES space for an additional null character. + minLen = vsnprintf(Jupiter::String_Type::str, Jupiter::String_Type::length + 1, format, args); + if (minLen < 0) return 0; + return Jupiter::String_Type::length = minLen; +} + +template<> size_t inline Jupiter::String_Loose::vformat(const wchar_t *format, va_list args) +{ + int minLen; + va_list sargs; + va_copy(sargs, args); + minLen = vswprintf(nullptr, 0, format, sargs); + va_end(sargs); + if (minLen < 0) return 0; // We simply can not work with this. + + this->setBufferSizeNoCopy(minLen + 1); // vsnprintf REQUIRES space for an additional null character. + minLen = vswprintf(Jupiter::String_Type::str, Jupiter::String_Type::length + 1, format, args); + if (minLen < 0) return 0; + return Jupiter::String_Type::length = minLen; +} + +template size_t Jupiter::String_Loose::vformat(const T *format, va_list args) +{ + return 0; +} + +// avformat() + +template<> size_t inline Jupiter::String_Loose::avformat(const char *format, va_list args) +{ + int minLen; + va_list sargs; + va_copy(sargs, args); + minLen = vsnprintf(nullptr, 0, format, sargs); + va_end(sargs); + if (minLen < 0) return 0; // We simply can not work with this. + + this->setBufferSize(Jupiter::String_Type::length + minLen + 1); // vsnprintf REQUIRES space for an additional null character. + minLen = vsnprintf(Jupiter::String_Type::str + Jupiter::String_Type::length + 1, minLen, format, args); + if (minLen <= 0) return 0; + Jupiter::String_Type::length += minLen; + return minLen; +} + +template<> size_t inline Jupiter::String_Loose::avformat(const wchar_t *format, va_list args) +{ + int minLen; + va_list sargs; + va_copy(sargs, args); + minLen = vswprintf(nullptr, 0, format, sargs); + va_end(sargs); + if (minLen < 0) return 0; // We simply can not work with this. + this->setBufferSize(minLen + Jupiter::String_Type::length + 1); // vsnprintf REQUIRES space for an additional null character. + + minLen = vswprintf(Jupiter::String_Type::str + Jupiter::String_Type::length + 1, minLen, format, args); + if (minLen <= 0) return 0; + Jupiter::String_Type::length += minLen; + return minLen; +} + +template size_t Jupiter::String_Loose::avformat(const T *format, va_list args) +{ + return 0; +} + +template Jupiter::String_Loose Jupiter::String_Loose::Format(const T *format, ...) +{ + String_Loose r; + va_list args; + va_start(args, format); + r.vformat(format, args); + va_end(args); + return r; +} + +template Jupiter::String_Loose Jupiter::String_Loose::substring(size_t pos) const +{ + return Jupiter::String_Loose::substring(*this, pos); +} + +template Jupiter::String_Loose Jupiter::String_Loose::substring(size_t pos, size_t length) const +{ + return Jupiter::String_Loose::substring(*this, pos, length); +} + +template Jupiter::String_Loose Jupiter::String_Loose::substring(const Jupiter::String_Type &in, size_t pos) +{ + return Jupiter::String_Type::substring(in, pos); +} + +template Jupiter::String_Loose Jupiter::String_Loose::substring(const T *in, size_t pos) +{ + return Jupiter::String_Type::substring(in, pos); +} + +template Jupiter::String_Loose Jupiter::String_Loose::substring(const Jupiter::String_Type &in, size_t pos, size_t len) +{ + return Jupiter::String_Type::substring(in, pos, len); +} + +template Jupiter::String_Loose Jupiter::String_Loose::substring(const T *in, size_t pos, size_t len) +{ + return Jupiter::String_Type::substring(in, pos, len); +} + +template Jupiter::String_Loose Jupiter::String_Loose::getWord(size_t pos, const T *whitespace) const +{ + return Jupiter::String_Loose::getWord(*this, pos, whitespace); +} + +template Jupiter::String_Loose Jupiter::String_Loose::getWord(const Jupiter::String_Type &in, size_t pos, const T *whitespace) +{ + return Jupiter::String_Type::getWord(in, pos, whitespace); +} + +template Jupiter::String_Loose Jupiter::String_Loose::getWord(const T *in, size_t pos, const T *whitespace) +{ + return Jupiter::String_Type::getWord(in, pos, whitespace); +} + +template Jupiter::String_Loose Jupiter::String_Loose::gotoWord(size_t pos, const T *whitespace) const +{ + return Jupiter::String_Loose::gotoWord(*this, pos, whitespace); +} + +template Jupiter::String_Loose Jupiter::String_Loose::gotoWord(const Jupiter::String_Type &in, size_t pos, const T *whitespace) +{ + return Jupiter::String_Type::gotoWord(in, pos, whitespace); +} + +template const Jupiter::String_Loose Jupiter::String_Loose::empty = Jupiter::String_Loose(); + +#endif // _STRING_IMP_H_HEADER \ No newline at end of file diff --git a/Release/Jupiter.lib b/Release/Jupiter.lib index 00b54d5739f838cafa5ed87248a0c047a280c5f0..f92f4c1283ead6639cb95f42db8de2e48146ed6e 100644 GIT binary patch delta 28347 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 Fe*oJMo$LSr delta 27834 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