Files
mlpack/fastlib/col/string.h
T
2007-09-06 17:15:26 +00:00

453 lines
11 KiB
C++

// Copyright 2007 Georgia Institute of Technology. All rights reserved.
// ABSOLUTELY NOT FOR DISTRIBUTION
/**
* @file string.h
*
* Simple non-stl string support.
*/
#ifndef COLLECTIONS_STRING_H
#define COLLECTIONS_STRING_H
#include "base/cc.h"
#include "arraylist.h"
#include <cstring>
/**
* Non-stl string with some simple features.
*
* The motivation for this is its ability to work well with ArrayList and
* supports our coding conventions. Beyond that, it has a few convenient
* tokenizers that you may find useful. Finally, it is non-templated,
* so compiler errors are easier to understand.
*
* WARNING: This has not gone through rigorous testing -- we expect it to
* work, but there may be some issues. You will be just fine using the
* STL string if you need string processing.
*/
class String {
private:
ArrayList<char> array_;
OT_DEF_BASIC(String) {
OT_MY_OBJECT(array_);
}
public:
/**
* Implicit conversion constructor.
*/
String(const char *s) {
Copy(s);
}
/**
* Initialize to empty string.
*/
void Init() {
array_.Init(1);
array_[0] = 0;
}
/**
* Allocate a buffer length -- this string won't really be a valid
* string until you fill the entire buffer.
*/
void Init(int finalLength) {
array_.Init(finalLength + 1);
}
/**
* Initialize the string in sprintf style.
*
* @param format the printf-style format string and arguments
*/
COMPILER_PRINTF(2, 3)
const String& InitSprintf(const char *format, ...);
/**
* Initializes as a copy of an existing region of characters.
* The existing array does not need to be null terminated.
*/
void Copy(const char *str_region_begin, index_t len) {
array_.Init(len + 1);
mem::Copy(array_.begin(), str_region_begin, len);
Terminate();
}
/**
* Initializes as a copy of a c-style string.
*/
void Copy(const char *str) {
array_.Copy(str, index_t(strlen(str) + 1));
}
/**
* Free up the string so you can reinitialize this to another string.
*/
void Destruct() {
array_.Destruct();
}
/**
* Swaps with another string.
*/
void Swap(String* other) {
array_.Swap(&other->array_);
}
/**
* Steals the string the other is pointing to, and "uninitializes"
* the string.
*/
void StealDestruct(String *other) {
array_.StealDestruct(&other->array_);
}
/**
*
*/
void Steal(ArrayList<char> *null_terminated_char_list) {
array_.Steal(null_terminated_char_list);
}
void Steal(char *str, index_t len, index_t capacity) {
array_.Steal(str, len + 1, capacity);
}
void Steal(char *str, index_t len) {
array_.Steal(str, len + 1, len + 1);
}
void Steal(char *str) {
Steal(str, strlen(str));
}
/** Implicit conversion to c-string. */
operator const char * () const
{ return array_.begin(); }
/** Returns the internally represented c-string. */
const char* c_str() const
{ return array_.begin(); }
/** Returns the internally represented c-string. */
char* c_str()
{ return array_.begin(); }
/** Returns a pointer to the first character. */
char* begin()
{ return array_.begin(); }
/** Returns a pointer to the first character. */
const char* begin() const
{ return array_.begin(); }
/** Returns a pointer to the null terminator character. */
const char *end() const {
return array_.end() - 1;
}
/** Returns a pointer to the null terminator character. */
char *end() {
return array_.end() - 1;
}
/** Returns the length of the string. */
index_t length() const
{ return array_.size() - 1; }
/**
* Reduces the length of the string to a particular
* location within this string (power user).
*
* @param s a pointer to a character in this string
*/
void Truncate(const char *s) {
array_.Resize(s - begin() + 1);
Terminate();
}
/**
* Truncates this string at a given length.
*
* @param newlen the new length to truncate to
*/
void Truncate(index_t newlen) {
array_.Resize(newlen + 1);
Terminate();
}
/**
* Sets the length of the string, if you expect to write past the end
* of this string (power user).
*/
void SetLength(index_t newlen) {
array_.Resize(newlen + 1);
Terminate();
}
/**
* Sets the length to the strlen of the string (power user, when
* boulding strings).
*/
void FixLength()
{ array_.Resize(strlen(array_.begin()) + 1); }
/**
* Puts a null terminator at the end of the string.
*/
void Terminate() {
*array_.last() = 0;
}
/**
* Minimizes the memory used after a lot of dynamic resizing.
*/
void Trim()
{ array_.Trim(); }
index_t Find(char c) const {
return IndexFromPtr(strchr(array_.begin(), c));
}
index_t FindR(char c) const {
return IndexFromPtr(strrchr(array_.begin(), c));
}
index_t Find(const char* s) const {
return IndexFromPtr(strstr(array_.begin(), s));
}
index_t FindAny(const char *char_set, index_t skip_initial = 0) const;
index_t IndexFromPtr(const char *position) const {
if (unlikely(!position)) {
return -1;
} else {
return index_t(position - begin());
}
}
/** Returns true if this string is zero length. */
bool is_empty() const
{ return array_.size() == 1; }
/**
* Appends another string to the end of this (power user).
*
* Amortized O(strlen(s)).
* You pass in the length of the string for speed reasons.
*
* @param add_str null-terminated string
* @param add_length the length of the string
*/
void Append(const char *add_str, index_t add_length) {
index_t mysize = array_.size();
array_.Resize(mysize + add_length);
strcpy(array_.begin() + mysize - 1, add_str);
}
/**
* Appends another string to the end of this.
* Amortized O(strlen(s)).
*/
void Append(const char *add_str) {
Append(add_str, strlen(add_str));
}
/**
* Appends a character to the end of this string.
* Amortized O(1).
*/
void Append(char c) {
*array_.last() = c;
*array_.AddBack() = '\0';
}
/**
* Appends another string to the end of this.
* Amortized O(o.length()).
*/
void Append(const String& str) {
Append(str.array_.begin(), str.length());
}
/**
* Appends another string to the end of this.
* Amortized O(o.length()).
*/
const String& operator += (const String& o) {
Append(o);
return *this;
}
/**
* Appends a character to the end of this string.
* Amortized O(1).
*/
const String& operator += (char c) {
Append(c);
return *this;
}
/**
* Appends another string to the end of this.
* Amortized O(strlen(s)).
*/
const String& operator += (const char *s) {
Append(s);
return *this;
}
/**
* Gets individual characters.
*/
char operator [] (index_t index) const
{ return array_[index]; }
/**
* Gets individual characters, and allows modification.
*/
char& operator [] (index_t index)
{ return array_[index]; }
/**
* Splits up the string like strtok.
*
* Starts at begin_index, skips initial delimeters.
* Proceeds to find any character in the delimeters or donechars.
* If it's a delimeter and no more max_portions has not been exceeded,
* a token is made. Processing stops when donechars are found.
*
* Example:
*
* @code
* String s;
* ArrayList<String> list;
* s.Copy("XXX,,,a, b;c; d! qrstuvk")
* list.Init();
* s.Split(3, ",; ", "!", 3, &list);
* // The result is: "a", "b", "c; d". (notice last two are one string)
* @endcode
*
* @param start_index the index to start at (initial characters to skip)
* @param delimeters the delimeter characters you are interested in
* @param donechars characters on which to stop (you can use "")
* @param max_portions the maximum number of portions (0 means unlimited)
* @param result the ArrayList to append results to (must be initialized)
* @return the index at which splitting stopped
*/
index_t Split(index_t start_index, const char *delimeters,
const char *donechars, index_t max_portions,
ArrayList<String> *result) const;
/**
* Splits up the string like strtok.
*
* Example:
*
* @code
* String s;
* ArrayList<String> list;
* s.Copy(",,a, b;c, d,,")
* list.Init();
* s.Split(",; ", &list);
* // The result is: "a", "b", "c", "d".
* @endcode
* *
* @param delimeters the delimeter characters you are interested in
* @param result the ArrayList to append results to (must be initialized)
* @return the index at which splitting stopped
*/
index_t Split(const char *delimeters, ArrayList<String> *result) const {
return Split(0, delimeters, "", 0, result);
}
/**
* Creates a new string with the specified characters removed from the left
* part of the string.
*/
void TrimLeft(const char *delimeters, String *result) const;
/**
* Creates a new string with the specified characters removed from the right
* part of the string.
*/
void TrimRight(const char *delimeters, String *result) const;
/**
* Creates a new string with the specified characters removed from the left
* and right parts of the string.
*/
void Trim(const char *delimeters, String *result) const;
/**
* Compares two strings case-insensitively.
*/
int CompareNoCase(const char *s) const {
return strcasecmp(array_.begin(), s);
}
/**
* Checks if two strings are equal.
*/
bool EqualsNoCase(const char *s) const {
return CompareNoCase(s) == 0;
}
/**
* Checks if this string begins with another string.
*/
bool StartsWith(const char *s) const {
return strncmp(array_.begin(), s, strlen(s)) == 0;
}
/**
* Compares two strings.
*
* If I am the lesser string, I return negative.
*/
int CompareTo(const String& other) const
{ return strcmp(begin(), other.begin()); }
/**
* Compares two strings.
*
* If I am the lesser string, I return negative.
*/
int CompareTo(const char* s) const
{ return strcmp(begin(), s); }
friend bool operator < (const String& a, const String& b) {
return strcmp(a.begin(), b.begin()) < 0;
}
friend bool operator == (const String& a, const String& b) {
return strcmp(a.begin(), b.begin()) == 0;
}
DEFINE_ALL_COMPARATORS(String);
friend bool operator < (const char *a, const String& b) {
// >
return strcmp(a, b.begin()) < 0;
}
friend bool operator < (const String& a, const char *b) {
// >
return strcmp(a.begin(), b) < 0;
}
friend bool operator == (const String& a, const char *b) {
return strcmp(a.begin(), b) == 0;
}
DEFINE_ALL_COMPARATORS_HETERO(String, const char *);
friend bool operator < (char a, const String& b) {
// >
DEBUG_ASSERT(b != '\0');
return a < b[0] || (unlikely(a == b[0]) && b[1] != '\0');
}
friend bool operator < (const String& a, char b) {
// >
DEBUG_ASSERT(b != '\0');
return a[0] < b;
}
friend bool operator == (const String& a, char b) {
DEBUG_ASSERT(b != '\0');
return a[0] == b && a[1] == '\0';
}
DEFINE_ALL_COMPARATORS_HETERO(String, char);
};
#endif