sources/mystring.cpp

branch
protocol5
changeset 150
37db42ad451a
parent 141
d9073c13dc98
parent 149
7643c21d546b
child 159
970d58a01e8b
--- a/sources/mystring.cpp	Wed Jul 20 15:03:37 2016 +0300
+++ b/sources/mystring.cpp	Wed Jul 20 17:56:40 2016 +0300
@@ -35,51 +35,42 @@
 
 BEGIN_ZFC_NAMESPACE
 
-// -------------------------------------------------------------------------------------------------
-//
+/*!
+ * \brief Compares this string with another.
+ * \param other The string to compare with.
+ * \returns -1 if this string is lexicographically less than \c other,
+ *          0 if they are equal, or
+ *          1 if this string is lexicographically greater than \c other.
+ */
 int String::compare (const String& other) const
 {
-	return m_string.compare (other.std_string());
-}
-
-// -------------------------------------------------------------------------------------------------
-//
-void String::trim (int n)
-{
-	if (n > 0)
-		m_string = mid (0, length() - n).std_string();
-	else
-		m_string = mid (n, -1).std_string();
+	return m_string.compare (other.stdString());
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-String String::strip (char unwanted) const
+/*!
+ * \brief Removes all instances of an unwanted character from this string.
+ * \param unwanted Character to remove.
+ */
+void String::strip (char unwanted)
 {
-	String result (m_string);
-
-	for (int pos = 0; (pos = result.find (unwanted)) != -1;)
-		result.remove_at (pos--);
-
-	return result;
+	for (int pos = 0; (pos = find (unwanted)) != -1;)
+		removeAt (pos--);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-String String::strip (const List<char>& unwanted) const
+/*!
+ * \brief Removes all instances of multiple characters from this string.
+ * \param unwanted Characters to remove.
+ */
+void String::strip (const List<char>& unwanted)
 {
-	String result (m_string);
-
-	for (String c : unwanted)
-	for (int pos = 0; (pos = result.find (c)) != -1;)
-		result.remove_at (pos--);
-
-	return result;
+	for (char character : unwanted)
+		strip(character);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-String String::to_uppercase() const
+/*!
+ * \returns an upper-case version of this string.
+ */
+String String::toUpperCase() const
 {
 	String result (m_string);
 
@@ -92,9 +83,10 @@
 	return result;
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-String String::to_lowercase() const
+/*!
+ * \returns a lower-case version of this string.
+ */
+String String::toLowerCase() const
 {
 	String result (m_string);
 
@@ -107,86 +99,99 @@
 	return result;
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-StringList String::split (char del) const
+/*!
+ * \brief Splits this string using the provided delimeter.
+ * \param delimeter Delimeter to use for splitting.
+ * \returns a string list containing the split strings.
+ */
+StringList String::split (char delimeter) const
 {
-	String delimstr;
-	delimstr += del;
-	return split (delimstr);
+	String delimeterString;
+	delimeterString += delimeter;
+	return split (delimeterString);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-StringList String::split (const String& del) const
+/*!
+ * \brief Splits this string using the provided delimeter.
+ * \param delimeter Delimeter to use for splitting.
+ * \returns a string list containing the split strings.
+ */
+StringList String::split (const String& delimeter) const
 {
-	StringList res;
+	StringList result;
 	int a = 0;
 	int b;
 
 	// Find all separators and store the text left to them.
-	while ((b = find (del, a)) != -1)
+	while ((b = find (delimeter, a)) != -1)
 	{
 		String sub = mid (a, b);
 
 		if (sub.length() > 0)
-			res << sub;
+			result << sub;
 
-		a = b + del.length();
+		a = b + delimeter.length();
 	}
 
 	// Add the string at the right of the last separator
 	if (a < (int) length())
-		res.append (mid (a, length()));
+		result.append (mid (a, length()));
 
-	return res;
+	return result;
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-void String::replace (const char* a, const char* b)
+/*!
+ * \brief Replaces all instances of \c text with \c replacement.
+ * \param text Text to replace away.
+ * \param replacement Text to replace \c text with.
+ */
+void String::replace (const char* text, const char* replacement)
 {
-	long pos;
+	int position;
 
-	while ((pos = find (a)) != -1)
-		m_string = m_string.replace (pos, strlen (a), b);
+	while ((position = find (text)) != -1)
+		m_string = m_string.replace (position, strlen (text), replacement);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-int String::count (char needle) const
+/*!
+ * \param character Character to count.
+ * \returns the amount of \c character found in the string.
+ */
+int String::count (char character) const
 {
 	int result = 0;
 
 	for (char ch : *this)
 	{
-		if (ch == needle)
+		if (ch == character)
 			result++;
 	}
 
 	return result;
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-// Returns a substring from [a, b)
-//
-String String::mid (int a, int b) const
+/*!
+ * \param a Starting index of the range.
+ * \param b Ending index of the range.
+ * \returns a sub-string containing all characters from \c a to \c b, not including the character at \c b.
+ */
+String String::mid (int rangeBegin, int rangeEnd) const
 {
-	a = max(a, 0);
-	b = min(b, length());
+	modifyIndex(rangeBegin);
+	modifyIndex(rangeEnd);
+	rangeBegin = max(rangeBegin, 0);
+	rangeEnd = min(rangeEnd, length());
 
-	if (b == -1)
-		b = length();
-
-	if (b <= a)
+	if (rangeEnd <= rangeBegin)
 		return "";
 	else
-		return m_string.substr(a, b - a);
+		return m_string.substr(rangeBegin, rangeEnd - rangeBegin);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
+/*!
+ * \param length Amount of characters to return.
+ * \returns the \c length right-most characters of the string.
+ */
 String String::right(int length) const
 {
 	if (length >= this->length())
@@ -195,90 +200,94 @@
 		return String(chars() + this->length() - length);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-int String::word_position (int n) const
+/*!
+ * \brief Finds the first instance of a sub-string.
+ * \param subString Sub-string to search within this string.
+ * \param startingPosition Position to start looking for the sub-string from.
+ * \returns the position the first instance of sub-string found, or -1 if not found.
+ */
+int String::find (const char* subString, int startingPosition) const
 {
-	int count = 0;
+	int position = m_string.find (subString, startingPosition);
+
+	if (position == int (std::string::npos))
+		return -1;
+	else
+		return position;
+}
+
+/*!
+ * \brief Finds the first instance of a character.
+ * \param character Character to search within this string.
+ * \param startingPosition Position to start looking for the character from.
+ * \returns the position of the first instance of the provided character found, or -1 if not found.
+ */
+int String::find (char character, int startingPosition) const
+{
+	int position = m_string.find (character, startingPosition);
 
-	for (char ch : *this)
+	if (position == int (std::string::npos))
+		return -1;
+	else
+		return position;
+}
+
+/*!
+ * \brief Finds the last instance of a sub-string.
+ * \param subString Sub-string to search within this string.
+ * \param startingPosition Position to start looking for the sub-string from.
+ * \returns the position the last instance of sub-string found, or -1 if not found.
+ */
+int String::findLast (const char* subString, int startingPosition) const
+{
+	modifyIndex(startingPosition);
+
+	for (; startingPosition > 0; startingPosition--)
 	{
-		if (not isspace(ch) or ++count < n)
-			continue;
+		if (strncmp (chars() + startingPosition, subString, strlen (subString)) == 0)
+			return startingPosition;
 	}
 
 	return -1;
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-int String::find (const char* c, int a) const
+/*!
+ * \brief Converts this string to an integer.
+ * \param ok An pointer to a boolean to store whether or not the conversion was successful.
+ *           If \c ok is \c NULL, the success state is not stored.
+ * \param base The base to interpret this string with.
+ * \returns the resulting integer.
+ */
+long String::toInt (bool* ok, int base) const
 {
-	int pos = m_string.find (c, a);
-
-	if (pos == int (std::string::npos))
-		return -1;
+	errno = 0;
+	char* endPointer;
+	long result = strtol (chars(), &endPointer, base);
 
-	return pos;
-}
+	if (ok != nullptr)
+		*ok = (errno == 0 and *endPointer == '\0');
 
-// -------------------------------------------------------------------------------------------------
-//
-int String::find (char ch, int a) const
-{
-	int pos = m_string.find (ch, a);
-
-	if (pos == int (std::string::npos))
-		return -1;
-
-	return pos;
+	return result;
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-int String::find_last (const char* c, int a) const
+/*!
+ * \brief Converts this string to a floating-point number.
+ * \param ok An pointer to a boolean to store whether or not the conversion was successful.
+ *           If \c ok is \c NULL, the success state is not stored.
+ * \returns the resulting floating-point number.
+ */
+float String::toFloat (bool* ok) const
 {
-	if (a == -1 or a >= length())
-		a = length() - 1;
-
-	for (; a > 0; a--)
-		if (m_string[a] == c[0] and strncmp (chars() + a, c, strlen (c)) == 0)
-			return a;
-
-	return -1;
+	return static_cast<float>(toDouble(ok));
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-long String::to_int (bool* ok, int base) const
-{
-	errno = 0;
-	char* endptr;
-	long i = strtol (chars(), &endptr, base);
-
-	if (ok)
-		*ok = (errno == 0 and *endptr == '\0');
-
-	return i;
-}
-
-// -------------------------------------------------------------------------------------------------
-//
-float String::to_float (bool* ok) const
-{
-	errno = 0;
-	char* endptr;
-	float i = (float) strtod (chars(), &endptr);
-
-	if (ok != nullptr)
-		*ok = (errno == 0 and *endptr == '\0');
-
-	return i;
-}
-
-// -------------------------------------------------------------------------------------------------
-//
-double String::to_double (bool* ok) const
+/*!
+ * \brief Converts this string to a double-precision floating-point number.
+ * \param ok An pointer to a boolean to store whether or not the conversion was successful.
+ *           If \c ok is \c NULL, the success state is not stored.
+ * \returns the resulting floating-point number.
+ */
+double String::toDouble (bool* ok) const
 {
 	errno = 0;
 	char* endptr;
@@ -290,93 +299,124 @@
 	return i;
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-String String::operator+ (const String& data) const
+/*!
+ * \brief Catenates this string with another string.
+ * \param text String to catenate to the end of this string.
+ * \returns the resulting string.
+ */
+String String::operator+ (const String& text) const
 {
 	String newString = *this;
-	newString.append (data);
+	newString.append (text);
+	return newString;
+}
+
+/*!
+ * \brief Catenates this string with another string.
+ * \param text String to catenate to the end of this string.
+ * \returns the resulting string.
+ */
+String String::operator+ (const char* text) const
+{
+	String newString = *this;
+	newString.append (text);
 	return newString;
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-String String::operator+ (const char* data) const
+/*!
+ * \returns whether or not this string represents a number.
+ */
+bool String::isNumeric() const
 {
-	String newstr = *this;
-	newstr.append (data);
-	return newstr;
+	char* endPointer;
+	strtol (chars(), &endPointer, 10);
+	return (endPointer != nullptr) and (*endPointer != '\0');
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-bool String::is_numeric() const
+/*!
+ * \param other Sub-string to find from the end of this string.
+ * \return whether or not this string ends with the provided sub-string.
+ */
+bool String::endsWith (const String& other) const
 {
-	char* endptr;
-	strtol (chars(), &endptr, 10);
-	return not (endptr && *endptr);
+	if (length() < other.length())
+	{
+		return false;
+	}
+	else
+	{
+		const int offset = length() - other.length();
+		return strncmp (chars() + offset, other.chars(), other.length()) == 0;
+	}
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-bool String::ends_with (const String& other)
+/*!
+ * \param other Sub-string to find from the beginning of this string.
+ * \returns whether or not this string begins with the provided sub-string.
+ */
+bool String::startsWith (const String& other) const
 {
 	if (length() < other.length())
 		return false;
-
-	const int ofs = length() - other.length();
-	return strncmp (chars() + ofs, other.chars(), other.length()) == 0;
+	else
+		return strncmp (chars(), other.chars(), other.length()) == 0;
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-bool String::starts_with (const String& other) const
-{
-	if (length() < other.length())
-		return false;
-
-	return strncmp (chars(), other.chars(), other.length()) == 0;
-}
-
-// -------------------------------------------------------------------------------------------------
-//
-void __cdecl String::sprintf (const char* fmtstr, ...)
+/*!
+ * \brief Formats this string using \c printf -like syntax.
+ * \param formatString Template string to use with formatting.
+ * \param ... Variadic arguments to use with formatting.
+ */
+void __cdecl String::sprintf (const char* formatString, ...)
 {
 	va_list args;
-	va_start (args, fmtstr);
-	this->vsprintf (fmtstr, args);
+	va_start (args, formatString);
+	this->vsprintf (formatString, args);
 	va_end (args);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-void String::vsprintf (const char* fmtstr, va_list args)
+/*!
+ * \brief Formats this string using \c vsnprintf, using the provided arguments.
+ * \param formatString Template string to use with formatting.
+ * \param args Variadic arguments to use with formatting.
+ */
+void String::vsprintf (const char* formatString, va_list args)
 {
-	char* buf = nullptr;
-	int bufsize = 256;
+	// Copy the argument list so that we have something to provide to vsnprintf in case we have to call it again.
+	va_list argsCopy;
+	va_copy(argsCopy, args);
 
-	do
+	// First, attempt to format using a fixed-size buffer.
+	static char buffer[1024];
+	size_t length = vsnprintf(buffer, sizeof buffer, formatString, args);
+
+	if (length < sizeof buffer)
 	{
-		bufsize *= 2;
-		delete[] buf;
-		buf = new char[bufsize];
+		// vsnprintf succeeded in fitting the formatted string into the buffer, so we're done.
+		m_string = buffer;
 	}
-	while (vsnprintf (buf, bufsize, fmtstr, args) >= bufsize);
-
-	m_string = buf;
-	delete[] buf;
+	else
+	{
+		// vsnprintf needs more space, so we have to allocate a new buffer and try again.
+		Vector<char> newBuffer(length + 1);
+		vsnprintf(newBuffer.data(), length + 1, formatString, argsCopy);
+		m_string = newBuffer;
+	}
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-String StringList::join (const String& delim)
+/*!
+ * \brief Joins the elements of this string list into one longer string.
+ * \param delimeter The delimeter to place between the element strings.
+ * \returns the catenated string.
+ */
+String StringList::join (const String& delimeter)
 {
 	String result;
 
 	for (const String &item : container())
 	{
-		if (result.is_empty() == false)
-			result += delim;
+		if (result.isEmpty() == false)
+			result += delimeter;
 
 		result += item;
 	}
@@ -384,13 +424,17 @@
 	return result;
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-bool String::mask_against (const String& pattern) const
+/*!
+ * \brief Tries to match this string against a mask pattern. In the pattern, '?' refers to one character, and '*' to
+ *        any number of characters.
+ * \param pattern The masking pattern to use for matching.
+ * \returns whether or not this string matches the provided pattern.
+ */
+bool String::maskAgainst (const String& pattern) const
 {
 	// Elevate to uppercase for case-insensitive matching
-	String pattern_upper = pattern.to_uppercase();
-	String this_upper = to_uppercase();
+	String pattern_upper = pattern.toUpperCase();
+	String this_upper = toUpperCase();
 	const char* maskstring = pattern_upper.chars();
 	const char* mptr = &maskstring[0];
 
@@ -432,71 +476,93 @@
 	return true;
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-String String::from_number (short int a)
+/*!
+ * \brief Converts a short integer into a string.
+ * \param value The value to convert.
+ * \returns the resulting string.
+ */
+String String::fromNumber (short int value)
 {
-	char buf[32];
-	::sprintf (buf, "%d", a);
-	return String (buf);
+	char buffer[32];
+	::sprintf (buffer, "%d", value);
+	return String (buffer);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-String String::from_number (int a)
+/*!
+ * \brief Converts an integer into a string.
+ * \param value The value to convert.
+ * \returns the resulting string.
+ */
+String String::fromNumber (int value)
 {
-	char buf[32];
-	::sprintf (buf, "%d", a);
-	return String (buf);
+	char buffer[32];
+	::sprintf (buffer, "%d", value);
+	return String (buffer);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-String String::from_number (long int a)
+/*!
+ * \brief Converts a long integer into a string.
+ * \param value The value to convert.
+ * \returns the resulting string.
+ */
+String String::fromNumber (long int value)
 {
-	char buf[32];
-	::sprintf (buf, "%ld", a);
-	return String (buf);
+	char buffer[32];
+	::sprintf (buffer, "%ld", value);
+	return String (buffer);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-String String::from_number (unsigned short int a)
+/*!
+ * \brief Converts an unsigned short integer into a string.
+ * \param value The value to convert.
+ * \returns the resulting string.
+ */
+String String::fromNumber (unsigned short int value)
 {
-	char buf[32];
-	::sprintf (buf, "%u", a);
-	return String (buf);
+	char buffer[32];
+	::sprintf (buffer, "%u", value);
+	return String (buffer);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-String String::from_number (unsigned int a)
+/*!
+ * \brief Converts an unsigned integer into a string.
+ * \param value The value to convert.
+ * \returns the resulting string.
+ */
+String String::fromNumber (unsigned int value)
 {
-	char buf[32];
-	::sprintf (buf, "%u", a);
-	return String (buf);
+	char buffer[32];
+	::sprintf (buffer, "%u", value);
+	return String (buffer);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-String String::from_number (unsigned long int a)
+/*!
+ * \brief Converts an unsigned long integer into a string.
+ * \param value The value to convert.
+ * \returns the resulting string.
+ */
+String String::fromNumber (unsigned long int value)
 {
-	char buf[32];
-	::sprintf (buf, "%lu", a);
-	return String (buf);
+	char buffer[32];
+	::sprintf (buffer, "%lu", value);
+	return String (buffer);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
-String String::from_number (double a)
+/*!
+ * \brief Converts a double-precision floating point number into a string, using the "%f" format specifier.
+ * \param value The value to convert.
+ * \returns the resulting string.
+ */
+String String::fromNumber (double value)
 {
-	char buf[64];
-	::sprintf (buf, "%f", a);
-	return String (buf);
+	char buffer[64];
+	::sprintf (buffer, "%f", value);
+	return String (buffer);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
+/*!
+ * \returns the MD5-checksum of this string.
+ */
 String String::md5() const
 {
 	char checksum[33];
@@ -505,8 +571,11 @@
 	return String (checksum);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
+/*!
+ * \brief Removes leading and trailing whitespace from this string. Alternatively a custom filter can be used to strip
+ *        something else than whitespace.
+ * \param filter The filtering function to use.
+ */
 void String::normalize (int (*filter)(int))
 {
 	int a = 0;
@@ -524,8 +593,10 @@
 		m_string = m_string.substr (a, b - a + 1);
 }
 
-// -------------------------------------------------------------------------------------------------
-//
+/*!
+ * \returns a version of this string without leading or trailing whitespace. Alternatively a custom filter can be used
+ *          to strip something else than whitespace.
+ */
 String String::normalized (int (*filter)(int)) const
 {
 	String result = *this;

mercurial