- #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"