sources/mystring.cpp

branch
protocol5
changeset 195
be953e1621d9
parent 159
970d58a01e8b
parent 191
2e6cbacafdc7
child 197
819fdef70d68
--- a/sources/mystring.cpp	Wed Jan 27 12:41:50 2021 +0200
+++ b/sources/mystring.cpp	Wed Jan 27 19:48:41 2021 +0200
@@ -1,5 +1,5 @@
 /*
-	Copyright 2014 - 2016 Teemu Piippo
+	Copyright 2014 - 2021 Teemu Piippo
 	All rights reserved.
 
 	Redistribution and use in source and binary forms, with or without
@@ -31,66 +31,17 @@
 #include <cstring>
 #include "main.h"
 #include "mystring.h"
-#include "md5.h"
 
 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.stdString());
-}
-
-/*!
- * \brief Removes all instances of an unwanted character from this string.
- * \param unwanted Character to remove.
- */
-void String::strip (char unwanted)
-{
-	for (int pos = 0; (pos = find (unwanted)) != -1;)
-		removeAt (pos--);
-}
-
-/*!
- * \brief Removes all instances of multiple characters from this string.
- * \param unwanted Characters to remove.
- */
-void String::strip (const List<char>& unwanted)
-{
-	for (char character : unwanted)
-		strip(character);
-}
-
-/*!
- * \returns an upper-case version of this string.
- */
-String String::toUpperCase() const
-{
-	String result (m_string);
-
-	for (char &ch : result)
-	{
-		if (islower(ch))
-			ch -= 'a' - 'A';
-	}
-
-	return result;
-}
-
-/*!
  * \returns a lower-case version of this string.
  */
-String String::toLowerCase() const
+std::string to_lowercase(const std::string& string)
 {
-	String result (m_string);
+	std::string result = string;
 
-	for (char &ch : result)
+	for (char& ch : result)
 	{
 		if (isupper(ch))
 			ch += 'a' - 'A';
@@ -100,74 +51,35 @@
 }
 
 /*!
- * \brief Splits this string using the provided delimeter.
- * \param delimeter Delimeter to use for splitting.
- * \returns a string list containing the split strings.
+ * \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.
  */
-StringList String::split (char delimeter) const
-{
-	String delimeterString;
-	delimeterString += delimeter;
-	return split (delimeterString);
-}
-
-/*!
- * \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
+std::string join_string_list(const std::vector<std::string>& strings, const std::string& delimeter)
 {
-	StringList result;
-	int a = 0;
-	int b;
-
-	// Find all separators and store the text left to them.
-	while ((b = find (delimeter, a)) != -1)
-	{
-		String sub = mid (a, b);
+	std::string result;
 
-		if (sub.length() > 0)
-			result << sub;
+	for (const std::string &item : strings)
+	{
+		if (not result.empty())
+			result += delimeter;
 
-		a = b + delimeter.length();
+		result += item;
 	}
 
-	// Add the string at the right of the last separator
-	if (a < (int) length())
-		result.append (mid (a, length()));
-
 	return result;
 }
 
 /*!
- * \brief Replaces all instances of \c text with \c replacement.
- * \param text Text to replace away.
- * \param replacement Text to replace \c text with.
+ * \brief Modifies the given index so that if it is negative, it is translated into a positive index starting from the
+ *        end of the string. For example, an index of -1 will be modified to point to the last character in the string,
+ *        -2 to the second last, etc.
+ * \param index Index to translate.
  */
-void String::replace (const char* text, const char* replacement)
+inline void modifyIndex(const std::string& str, int& index)
 {
-	int position;
-
-	while ((position = find (text)) != -1)
-		m_string = m_string.replace (position, strlen (text), replacement);
-}
-
-/*!
- * \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 == character)
-			result++;
-	}
-
-	return result;
+	if (index < 0)
+		index = str.length() - index;
 }
 
 /*!
@@ -175,204 +87,29 @@
  * \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
+std::string mid(const std::string& str, int rangeBegin, int rangeEnd)
 {
-	modifyIndex(rangeBegin);
-	modifyIndex(rangeEnd);
+	modifyIndex(str, rangeBegin);
+	modifyIndex(str, rangeEnd);
 	rangeBegin = max(rangeBegin, 0);
-	rangeEnd = min(rangeEnd, length());
+	rangeEnd = min(rangeEnd, static_cast<signed>(str.length()));
 
 	if (rangeEnd <= rangeBegin)
 		return "";
 	else
-		return m_string.substr(rangeBegin, rangeEnd - rangeBegin);
+		return str.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())
-		return *this;
-	else
-		return String(chars() + this->length() - length);
-}
-
-/*!
- * \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 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);
-
-	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 (strncmp (chars() + startingPosition, subString, strlen (subString)) == 0)
-			return startingPosition;
-	}
-
-	return -1;
-}
-
-/*!
- * \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
-{
-	errno = 0;
-	char* endPointer;
-	long result = strtol (chars(), &endPointer, base);
-
-	if (ok != nullptr)
-		*ok = (errno == 0 and *endPointer == '\0');
-
-	return result;
-}
-
-/*!
- * \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
+std::string right(const std::string& str, int length)
 {
-	return static_cast<float>(toDouble(ok));
-}
-
-/*!
- * \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;
-	double i = strtod (chars(), &endptr);
-
-	if (ok != nullptr)
-		*ok = (errno == 0 and *endptr == '\0');
-
-	return i;
-}
-
-/*!
- * \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 (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;
-}
-
-/*!
- * \returns whether or not this string represents a number.
- */
-bool String::isNumeric() const
-{
-	char* endPointer;
-	strtol (chars(), &endPointer, 10);
-	return (endPointer != nullptr) and (*endPointer != '\0');
-}
-
-/*!
- * \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
-{
-	if (length() < other.length())
-	{
-		return false;
-	}
+	if (length >= static_cast<signed>(str.length()))
+		return str;
 	else
-	{
-		const int offset = length() - other.length();
-		return strncmp (chars() + offset, other.chars(), other.length()) == 0;
-	}
-}
-
-/*!
- * \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;
-	else
-		return strncmp (chars(), other.chars(), other.length()) == 0;
-}
-
-/*!
- * \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, formatString);
-	this->vsprintf (formatString, args);
-	va_end (args);
+		return std::string{str.data() + str.length() - length};
 }
 
 /*!
@@ -380,8 +117,10 @@
  * \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)
+std::string vsprintf(const char* formatString, va_list args)
 {
+	std::string result;
+
 	// 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);
@@ -393,192 +132,118 @@
 	if (length < sizeof buffer)
 	{
 		// vsnprintf succeeded in fitting the formatted string into the buffer, so we're done.
-		m_string = buffer;
+		result = buffer;
 	}
 	else
 	{
 		// vsnprintf needs more space, so we have to allocate a new buffer and try again.
-		Vector<char> newBuffer(length + 1);
+		std::vector<char> newBuffer(length + 1);
 		vsnprintf(newBuffer.data(), length + 1, formatString, argsCopy);
-		m_string = newBuffer;
+		result = newBuffer.data();
+	}
+	
+	return result;
+}
+
+/*!
+ * \brief Formats this string using \c printf -like syntax.
+ * \param formatString Template string to use with formatting.
+ * \param ... Variadic arguments to use with formatting.
+ */
+std::string __cdecl sprintf(const char* formatString, ...)
+{
+	va_list args;
+	va_start (args, formatString);
+	std::string result = vsprintf(formatString, args);
+	va_end (args);
+	return result;
+}
+
+std::string remove_range(const std::string &string, int start, int end)
+{
+	std::string result;
+	result.reserve(string.length() - (end - start));
+	std::copy(string.begin(), string.begin() + start, std::back_inserter(result));
+	std::copy(string.begin() + end, string.end(), std::back_inserter(result));
+	return result;
+}
+
+
+/*!
+ * \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 starts_with(const std::string& str, const std::string& other)
+{
+	if (str.length() < other.length())
+		return false;
+	else
+		return std::strncmp(str.data(), other.data(), other.length()) == 0;
+}
+
+/*!
+ * \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 replace_all(std::string& str, const char* text, const char* replacement)
+{
+	int position;
+	while ((position = str.find(text)) != -1)
+	{
+		str.replace(position, std::strlen(text), replacement);
 	}
 }
 
 /*!
- * \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.
+ * \brief Splits this string using the provided delimeter.
+ * \param delimeter Delimeter to use for splitting.
+ * \returns a string list containing the split strings.
  */
-String StringList::join (const String& delimeter)
+std::vector<std::string> split(const std::string& string, const std::string& delimeter)
 {
-	String result;
+	std::vector<std::string> result;
+	int a = 0;
+	int b;
 
-	for (const String &item : container())
+	// Find all separators and store the text left to them.
+	while ((b = string.find(delimeter, a)) != -1)
 	{
-		if (result.isEmpty() == false)
-			result += delimeter;
+		std::string sub = mid(string, a, b);
+
+		if (sub.length() > 0)
+			result.push_back(sub);
 
-		result += item;
+		a = b + delimeter.length();
 	}
 
+	// Add the string at the right of the last separator
+	if (a < static_cast<int>(string.length()))
+		result.push_back(mid(string, a, string.length()));
+
 	return result;
 }
 
 /*!
- * \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.
+ * \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.
  */
-bool String::maskAgainst (const String& pattern) const
-{
-	// Elevate to uppercase for case-insensitive matching
-	String pattern_upper = pattern.toUpperCase();
-	String this_upper = toUpperCase();
-	const char* maskstring = pattern_upper.chars();
-	const char* mptr = &maskstring[0];
-
-	for (const char* sptr = this_upper.chars(); *sptr != '\0'; sptr++)
-	{
-		if (*mptr == '?')
-		{
-			if (*(sptr + 1) == '\0')
-			{
-				// ? demands that there's a character here and there wasn't.
-				// Therefore, mask matching fails
-				return false;
-			}
-		}
-		else if (*mptr == '*')
-		{
-			char end = *(++mptr);
-
-			// If '*' is the final character of the message, all of the remaining
-			// string matches against the '*'. We don't need to bother checking
-			// the string any further.
-			if (end == '\0')
-				return true;
-
-			// Skip to the end character
-			while (*sptr != end and *sptr != '\0')
-				sptr++;
-
-			// String ended while the mask still had stuff
-			if (*sptr == '\0')
-				return false;
-		}
-		else if (*sptr != *mptr)
-			return false;
-
-		mptr++;
-	}
-
-	return true;
-}
-
-/*!
- * \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 buffer[32];
-	::sprintf (buffer, "%d", value);
-	return String (buffer);
-}
-
-/*!
- * \brief Converts an integer into a string.
- * \param value The value to convert.
- * \returns the resulting string.
- */
-String String::fromNumber (int value)
+std::optional<long> to_int(const char* str, int base)
 {
-	char buffer[32];
-	::sprintf (buffer, "%d", value);
-	return String (buffer);
-}
-
-/*!
- * \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 buffer[32];
-	::sprintf (buffer, "%ld", value);
-	return String (buffer);
-}
-
-/*!
- * \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 buffer[32];
-	::sprintf (buffer, "%u", value);
-	return String (buffer);
-}
-
-/*!
- * \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 buffer[32];
-	::sprintf (buffer, "%u", value);
-	return String (buffer);
-}
-
-/*!
- * \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 buffer[32];
-	::sprintf (buffer, "%lu", value);
-	return String (buffer);
-}
-
-/*!
- * \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 buffer[64];
-	::sprintf (buffer, "%f", value);
-	return String (buffer);
-}
-
-/*!
- * \brief Constructs a string from a vector of bytes. The bytes do not have to be null-terminated.
- * \param bytes Bytes to use for construction
- * \returns the resulting string.
- */
-String String::fromBytes(const ByteArray& bytes)
-{
-	return String(reinterpret_cast<const Vector<char>&>(bytes));
-}
-
-/*!
- * \returns the MD5-checksum of this string.
- */
-String String::md5() const
-{
-	char checksum[33];
-	CalculateMD5 (reinterpret_cast<const unsigned char*> (chars()), length(), checksum);
-	checksum[sizeof checksum - 1] = '\0';
-	return String (checksum);
+	errno = 0;
+	char* endPointer;
+	long result = strtol(str, &endPointer, base);
+	if (errno == 0 and *endPointer == '\0')
+	{
+		return result;
+	}
+	else
+	{
+		return {};
+	}
 }
 
 /*!
@@ -586,32 +251,26 @@
  *        something else than whitespace.
  * \param filter The filtering function to use.
  */
-void String::normalize (int (*filter)(int))
+void normalize(std::string& string, int (*filter)(int))
 {
 	int a = 0;
-	int b = length() - 1;
-
-	while ((*filter) (m_string[a]) and a != b)
+	int b = string.length() - 1;
+	while ((*filter)(string[a]) and a != b)
+	{
 		++a;
-
-	while ((*filter) (m_string[b]) and a != b)
+	}
+	while ((*filter)(string[b]) and a != b)
+	{
 		--b;
-
+	}
 	if (a == b)
-		m_string = "";
-	else if (a != 0 or b != length() - 1)
-		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;
-	result.normalize(filter);
-	return result;
+	{
+		string = "";
+	}
+	else if (a != 0 or b != static_cast<signed>(string.length() - 1))
+	{
+		string = string.substr (a, b - a + 1);
+	}
 }
 
 END_ZFC_NAMESPACE

mercurial