- #pragma once
- #include "allocator.h"
- #include "assert.h"
- #include "array.h"
- #include <string.h>
- #include <stdlib.h>
- #include <limits.h>
- namespace stingray_plugin_foundation {
- template <class T> class Vector;
- // ----------------------------------------------------------------------
- // Functions that extend the normal ANSI C string interface.
- // ----------------------------------------------------------------------
- // Returns the length of the string a 32-bit number (unsigned rather
- // than size_t).
- inline unsigned strlen32(const char *s);
- // Returns the length of the string a 32-bit number (unsigned rather
- // than size_t).
- inline unsigned strlenw32(const wchar_t *s);
- // Returns true if strings s1 and s2 are identical.
- inline bool strequal(const char *s1, const char *s2);
- // Returns true if strings s1 and s2 are identical when ignoring case.
- // Only ascii characters (A-Z) are considered when comparing case.
- bool strequali(const char *s1, const char *s2);
- // Returns true if string s is empty.
- inline bool strempty(const char *s);
- // Converts s to an integer and returns the result.
- inline int to_int(const char *s);
- // Converts s to an unsigned and returns the result.
- inline unsigned to_unsigned(const char *s);
- // Converts s to a float and returns the result.
- inline float to_float(const char *s);
- // Converts s to an integer and returns the result.
- inline int to_int(const char *s, bool &error);
- // Converts s to an unsigned and returns the result.
- inline unsigned to_unsigned(const char *s, bool &error);
- // Converts s to a float and returns the result.
- inline float to_float(const char *s, bool &error);
- // ----------------------------------------------------------------------
- // A thin wrapper around a const char * that just adds a == operator for string
- // comparison. Note especially that it doesn't make a copy of the string. The
- // original string pointer must be valid as long as this class is used.
- //
- // Typically, this class is used to make string comparisons easier to read
- // and prevent mistakes. An example:
- //
- //  ConstString s(p)
- //      if (s == "open")
- //          ...
- class ConstString
- {
- public:
-     // ConstString that wraps the empty string.
-     ConstString() : s("") {}
-     // ConstString that wraps the specified string.
-     ConstString(const char *s_) : s(s_) {}
-     // Returns the raw string pointer.
-     const char *c_str() const {return s;}
-     // Returns true if the string is empty.
-     bool empty() const {return *s == 0;}
-     // Returns the length of the string
-     unsigned size() const {return strlen32(s);}
-     const char *s;
- };
- // Comparison operators for ConstString.
- inline bool operator==(const ConstString &s1, const char *s2) {return strcmp(s1.s, s2) ==  0;}
- inline bool operator==(const char *s1, const ConstString &s2) {return strcmp(s1, s2.s) ==  0;}
- inline bool operator==(const ConstString &s1, const ConstString &s2) {return strcmp(s1.s, s2.s) == 0;}
- inline bool operator!=(const ConstString &s1, const char *s2) {return strcmp(s1.s, s2) !=  0;}
- inline bool operator!=(const char *s1, const ConstString &s2) {return strcmp(s1, s2.s) !=  0;}
- inline bool operator!=(const ConstString &s1, const ConstString &s2) {return strcmp(s1.s, s2.s) != 0;}
- inline bool operator<(const ConstString &s1, const char *s2) {return strcmp(s1.s, s2) <  0;}
- inline bool operator<(const char *s1, const ConstString &s2) {return strcmp(s1, s2.s) <  0;}
- inline bool operator<(const ConstString &s1, const ConstString &s2) {return strcmp(s1.s, s2.s) < 0;}
- // ----------------------------------------------------------------------
- // Class that represents a dynamic string -- a string whose content can be modified.
- // This class is basically just a thin wrapper around an Array<char> buffer that stores
- // the content of the string.
- class DynamicString
- {
- public:
-     ALLOCATOR_AWARE;
-     // Creates a new dynamic string using the specified allocator.
-     DynamicString(Allocator &a) : _buffer(a) {}
-     // Creates a new dynamic string initialized from s.
-     DynamicString(Allocator &a, const char *s) : _buffer(a) { unsigned length = s ? strlen32(s) : 0;  if (length > 0) { _buffer.resize(length + 1);  memmove(_buffer.begin(), s, _buffer.size()); } }
-     // Creates a new dynamic string initialized from the first n characters of s.
-     DynamicString(Allocator &a, const char *s, unsigned n) : _buffer(a) { if (n > 0) { _buffer.resize(n + 1);  memmove(_buffer.begin(), s, n); _buffer[n] = 0; } }
-     // Copy constructor
-     DynamicString(const DynamicString &o) : _buffer(o._buffer) {}
-     // Assignment.
-     void operator=(const char *s) { unsigned length = strlen32(s); if (length > 0) { _buffer.resize(length + 1); memmove(_buffer.begin(), s, _buffer.size()); } else _buffer.clear(); }
-     // Assigns the characters from ds to this string. Does not change the allocator.
-     void operator=(const DynamicString &ds) { _buffer = ds._buffer; }
-     // Returns the size/length of the string. The size does not include the terminating zero.
-     unsigned size() const {return _buffer.empty() ? 0 : _buffer.size() - 1;}
-     // Returns true if the string is empty.
-     bool empty() const {return size() == 0;}
-     // Returns the C-string held by this dynamic string.
-     char *c_str() { return _buffer.empty() ? empty_string() : _buffer.begin(); }
-     const char *c_str() const {return _buffer.empty() ? empty_string() : _buffer.begin();}
-     // Returns a pointer to the terminating zero at the end of C-string.
-     char *end() { return _buffer.empty() ? c_str() : _buffer.end() - 1; }
-     const char *end() const { return _buffer.empty() ? c_str() : _buffer.end() - 1; }
-     // Accesses characters in the string.
-     char &operator[](unsigned i) { return c_str()[i];}
-     const char &operator[](unsigned i) const { return c_str()[i]; }
-     // Resizes the string to the specified size (size does not include terminating zero).
-     void resize(unsigned size) { bool empty = _buffer.empty(); _buffer.resize(size + 1); if (empty) _buffer[0] = '\0'; _buffer[size] = '\0'; }
-     // Extends the string with the specified number of bytes.
-     void extend(unsigned bytes) {resize(size() + bytes);}
-     // Clears the memory and sets this string to the empty string.
-     void clear() { _buffer.clear(); }
-     // Returns the allocator of the string.
-     Allocator &allocator() const {return _buffer.allocator();}
-     // Swaps the contents efficiently.
-     void swap(DynamicString &other);
-     // Serializes the string to the stream
-     template <class STREAM> void serialize(STREAM &s) {
-         unsigned sz = size();
-         s & sz;
-         if (sz != size())
-             resize(sz);
-         if (sz != 0) {
-             if (s.is_output())
-                 s.write(_buffer.begin(), sz);
-             else
-                 s.read(_buffer.begin(), sz);
-         }
-     }
-     Array<char> &buffer() { if (_buffer.empty()) _buffer.push_back(0); return _buffer; }
-     private:
-         // Raw access to the string buffer.
-         Array<char> _buffer;
-         static char *empty_string() { static char c = '\0'; return &c; }
- };
- // Comparison operators
- inline bool operator==(const DynamicString &s1, const char *s2) {return strcmp(s1.c_str(), s2) ==  0;}
- inline bool operator==(const char *s1, const DynamicString &s2) {return strcmp(s1, s2.c_str()) ==  0;}
- inline bool operator==(const DynamicString &s1, const DynamicString &s2) {return strcmp(s1.c_str(), s2.c_str()) == 0;}
- inline bool operator!=(const DynamicString &s1, const char *s2) {return strcmp(s1.c_str(), s2) !=  0;}
- inline bool operator!=(const char *s1, const DynamicString &s2) {return strcmp(s1, s2.c_str()) !=  0;}
- inline bool operator!=(const DynamicString &s1, const DynamicString &s2) {return strcmp(s1.c_str(), s2.c_str()) != 0;}
- inline bool operator<(const DynamicString &s1, const char *s2) {return strcmp(s1.c_str(), s2) <  0;}
- inline bool operator<(const char *s1, const DynamicString &s2) {return strcmp(s1, s2.c_str()) <  0;}
- inline bool operator<(const DynamicString &s1, const DynamicString &s2) {return strcmp(s1.c_str(), s2.c_str()) < 0;}
- // Appends `s` to the end of `str`.
- inline void append(DynamicString &str, const char *s);
- // Appends `c` to the end of `str`.
- inline void append(DynamicString &str, char c);
- // Appends `len` characters beginning from `s` to the end of `str`.
- inline void append(DynamicString &str, const char *s, unsigned len);
- // Inserts `s` in front of any characters in `str`.
- inline void prefix(DynamicString &str, const char *s);
- // ----------------------------------------------------------------------
- // Namespace for string operations.
- namespace string {
-     const unsigned npos = UINT_MAX;
-     // Returns true if c is a whitespace character.
-     bool is_whitespace(char c);
-     // Returns the index of the first occurrence of `c` in
-     // `s` or `npos` if not found.
-     unsigned find(const char *s, char c);
-     // Returns the index of the last occurrence of `c` in
-     // `s` or `npos` if not found.
-     unsigned find_last(const char *s, char c);
-     // Returns the index of the first occurrence of `substring` in
-     // `s` or `npos` if not found.
-     unsigned find(const char *s, const char *substring);
-     // Returns the index of the last occurrence of `substring` in
-     // `s` or `npos` if not found.
-     unsigned find_last(const char *s, const char *substring);
-     // Returns true if `s` contains `substring`.
-     bool contains(const char *s, const char *substring);
-     // Splits the string `s` on the first instance of `split_on` and stores the
-     // results in `first` and `second`. If `split_on` is not found, `first`
-     // will get the entire string.
-     void split(const char *s, const char *split_on, DynamicString &first, DynamicString &second);
-     // Splits the string `s` on all instances of `split_on` and stores the
-     // results in `result`
-     void split(const char *s, const char *split_by, Vector<DynamicString> &result);
-     enum SkipEmpty { SKIP_EMPTY, DONT_SKIP_EMPTY };
-     // Joins each string in `strings` into a single string separated by `separator` and stores the result in `result`.
-     void join(const DynamicString* strings, unsigned num_strings, const char* separator, DynamicString& result, SkipEmpty skip_empty = DONT_SKIP_EMPTY);
-     // Returns a pointer to a string with n spaces for indentation purposes. If n > 200 a string with 200 spaces
-     // will be returned.
-     const char *spaces(int n);
-     // Returns true if s is a lowercase string.
-     bool is_lowercase(const char *s);
-     // Replaces the character range (start, start+size) in the string s with the
-     // replacement rep.
-     void replace(DynamicString &s, unsigned start, unsigned size, const char *rep);
-     // Replaces the occurances of the string `find` with the replacement `rep` and returns the number of successful replacements made.
-     unsigned replace_all(DynamicString &s, const char *find, const char *rep);
-     // In-place converts the string to lower case
-     void to_lower_case(char *s);
-     // In-place converts the string to upper case
-     void to_upper_case(char *s);
-     // Converts from camel case to underscore representation.
-     DynamicString from_camel_case(const char *s, Allocator &a);
-     // Returns the string with the character stripped out.
-     DynamicString strip(const char *s, char c, Allocator &a);
-     // Trims whitespace from the start and end of the string and returns the result.
-     DynamicString trim(const char *s, Allocator &a);
-     // Returns a substring of s starting at start and of length.
-     DynamicString substring(const char *s, unsigned start, unsigned length, Allocator &a);
-     // Returns true if `str` contains `c`.
-     bool in_string(const char *str, char c);
-     // Returns true if `str` only contains characters in `allowed`.
-     bool consists_of(const char *str, const char *allowed);
-     // Returns true if `str` begins with `begins`.
-     bool begins_with(const char *str, const char *begins);
-     // Returns true if `str` ends with `ends`.
-     bool ends_with(const char *str, const char *ends);
-     bool ends_with(const wchar_t *str, const wchar_t *ends);
-     // Returns a copy of the string `str` allocated with the allocator `a`.
-     char* copy(const char *str, Allocator& a);
-     // Copies src to dest. Truncates the copy if necessary so that more than
-     // `dest_size` bytes are never written to `dest`. Always terminates
-     // dest with a \0 character. Utf-8 characters are guaranteed to not get
-     // truncated in the middle of a multibyte character.
-     void copy(char *dest, const char *src, unsigned dest_size);
-     void copy(wchar_t *dest, const wchar_t *src, unsigned dest_size);
-     // Appends `src` to the end of `dest`. Truncates `dest` if necessary so that
-     // more than `dest_size` bytes are never written to `dest`. Always terminates
-     // dest with a \0 character. Utf-8 characters are guaranteed to not get
-     // truncated in the middle of a multibyte character.
-     void append(char *dest, const char *src, unsigned dest_size);
-     void append(wchar_t *dest, const wchar_t *src, unsigned dest_size);
-     #ifdef DEVELOPMENT
-         // Returns a string allocated by `a` representing a typcial hex_view of the `data`.
-         // (Such as shown by a memory debugger, for instance.)
-         // `columns` is the number of columns of hex values in the view.
-         // If `ascii_column` is true a column that shows ascii representation is included.
-         DynamicString hex_view(Allocator &a, const char *data, unsigned size, unsigned columns = 16, bool ascii_column = true);
-     #endif
- } // namespace string
- }
- #include "string.inl"