1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
|
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
//=============================================================================
//
// String class with simple memory management and copy-on-write behavior.
//
// String objects do reference counting and share data buffer on assignment.
// The reallocation and copying is done only when the string is modified.
//
// The copying of memory inside buffer is reduced to minimum. If the string is
// truncated, it is not aligned to buffer head each time, instead the c-str
// pointer is advanced, or null-terminator is put on the new place. Similarly,
// when string is enlarged and new characters are prepended or appended, only
// c-str pointer and null-terminator's position are changed, if there's enough
// space before and after meaningful string data.
//
// The class provides means to reserve large amount of buffer space before
// making modifications, as well as compacting buffer to minimal size.
//
// For all methods that expect C-string as parameter - if the null pointer is
// passed in place of C-string it is treated in all aspects as a valid empty
// string.
//
//=============================================================================
#ifndef AGS_SHARED_UTIL_STRING_H
#define AGS_SHARED_UTIL_STRING_H
//include <stdarg.h>
#include "common/str.h"
#include "common/std/vector.h"
#include "ags/shared/core/platform.h"
#include "ags/shared/core/types.h"
namespace AGS3 {
namespace AGS {
namespace Shared {
class Stream;
class String {
public:
static const size_t NoIndex = (size_t)-1;
// Standard constructor: intialize empty string
String();
// Copy constructor
String(const String &);
// Move constructor
String(String &&);
// Initialize with C-string
String(const char *cstr);
// Initialize by copying up to N chars from C-string
String(const char *cstr, size_t length);
// Initialize by filling N chars with certain value
String(char c, size_t count);
// Initialize from a ScummVM string
String(const Common::String &s);
~String();
// Get underlying C-string for reading; this method guarantees valid C-string
inline const char *GetCStr() const {
return _cstr;
}
// Get character count
inline size_t GetLength() const {
return _len;
}
// Know if the string is empty (has no meaningful characters)
inline bool IsEmpty() const {
return _len == 0;
}
// Tells if the string is either empty or has only whitespace characters
bool IsNullOrSpace() const;
// Those getters are for tests only, hence if AGS_PLATFORM_TEST
#if defined(AGS_PLATFORM_TEST) && AGS_PLATFORM_TEST
inline const char *GetBuffer() const {
return _buf;
}
inline size_t GetCapacity() const {
return _bufHead ? _bufHead->Capacity : 0;
}
inline size_t GetRefCount() const {
return _bufHead ? _bufHead->RefCount : 0;
}
#endif
// Read() method implies that string length is initially unknown.
// max_chars parameter determine the buffer size limit.
// If stop_at_limit flag is set, it will read only up to the max_chars.
// Otherwise (by default) hitting the limit won't stop stream reading;
// the data will be read until null-terminator or EOS is met, and buffer
// will contain only leftmost part of the longer string that fits in.
// This method is better fit for reading from binary streams.
void Read(Stream *in, size_t max_chars = 5 * 1024 * 1024, bool stop_at_limit = false);
// ReadCount() reads up to N characters from stream, ignoring null-
// terminator. This method is better fit for reading from text
// streams, or when the length of string is known beforehand.
void ReadCount(Stream *in, size_t count);
// Write() puts the null-terminated string into the stream.
void Write(Stream *out) const;
// WriteCount() writes N characters to stream, filling the remaining
// space with null-terminators when needed.
void WriteCount(Stream *out, size_t count) const;
//-------------------------------------------------------------------------
// String analysis methods
//-------------------------------------------------------------------------
// Compares with given string
int Compare(const String &str) const {
return Compare(str._cstr);
}
int Compare(const char *cstr) const;
int CompareNoCase(const String &str) const {
return CompareNoCase(str._cstr);
}
int CompareNoCase(const char *cstr) const;
// Compares the leftmost part of this string with given string
int CompareLeft(const String &str, size_t count = -1) const {
return CompareLeft(str._cstr, count != NoIndex ? count : str._len);
}
int CompareLeft(const char *cstr, size_t count = -1) const;
int CompareLeftNoCase(const String &str, size_t count = -1) const {
return CompareLeftNoCase(str._cstr, count != NoIndex ? count : str._len);
}
int CompareLeftNoCase(const char *cstr, size_t count = -1) const;
// Compares any part of this string with given string
int CompareMid(const String &str, size_t from, size_t count = -1) const {
return CompareMid(str._cstr, from, count != NoIndex ? count : str._len);
}
int CompareMid(const char *cstr, size_t from, size_t count = -1) const;
int CompareMidNoCase(const String &str, size_t from, size_t count = -1) const {
return CompareMidNoCase(str._cstr, from, count != NoIndex ? count : str._len);
}
int CompareMidNoCase(const char *cstr, size_t from, size_t count = -1) const;
// Compares the rightmost part of this string with given C-string
int CompareRight(const String &str, size_t count = -1) const {
return CompareRight(str._cstr, count != NoIndex ? count : str._len);
}
int CompareRight(const char *cstr, size_t count = -1) const;
int CompareRightNoCase(const String &str, size_t count = -1) const {
return CompareRightNoCase(str._cstr, count != NoIndex ? count : str._len);
}
int CompareRightNoCase(const char *cstr, size_t count = -1) const;
// Convenience aliases for Compare functions
inline bool Equals(const String &str) const {
return Compare(str) == 0;
}
inline bool Equals(const char *cstr) const {
return Compare(cstr) == 0;
}
inline bool StartsWith(const String &str) const {
return CompareLeft(str) == 0;
}
inline bool StartsWith(const char *cstr) const {
return CompareLeft(cstr) == 0;
}
inline bool EndsWidth(const String &str) const {
return CompareRight(str) == 0;
}
inline bool EndsWidth(const char *cstr) const {
return CompareRight(cstr) == 0;
}
// These functions search for character or substring inside this string
// and return the index of the (first) character, or -1 if nothing found.
size_t FindChar(char c, size_t from = 0) const;
size_t FindCharReverse(char c, size_t from = -1) const;
size_t FindString(const String &str, size_t from = 0) const {
return FindString(str._cstr, from);
}
size_t FindString(const char *cstr, size_t from = 0) const;
// Section methods treat string as a sequence of 'fields', separated by
// special character. They search for a substring consisting of all such
// 'fields' from the 'first' to the 'last', inclusive; the bounding
// separators are optionally included too.
// Section indexes are zero-based. The first (0th) section is always
// located before the first separator and the last section is always
// located after the last separator, meaning that if the outermost
// character in string is separator char, there's still an empty trailing
// field beyond that.
// This also means that there's always at least one section in any string,
// even if there are no separating chars.
bool FindSection(char separator, size_t first, size_t last, bool exclude_first_sep, bool exclude_last_sep,
size_t &from, size_t &to) const;
// Get Nth character with bounds check (as opposed to subscript operator)
inline char GetAt(size_t index) const {
return (index < _len) ? _cstr[index] : 0;
}
inline char GetLast() const {
return (_len > 0) ? _cstr[_len - 1] : 0;
}
//-------------------------------------------------------------------------
// Value cast methods
//-------------------------------------------------------------------------
int ToInt() const;
//-------------------------------------------------------------------------
// Factory methods
//-------------------------------------------------------------------------
// Wraps the given string buffer without owning it, won't count references,
// won't delete it at destruction. Can be used with string literals.
static String Wrapper(const char *cstr);
// TODO: investigate C++11 solution for variadic templates (would that be more convenient here?)
static String FromFormat(const char *fcstr, ...);
static String FromFormatV(const char *fcstr, va_list argptr);
// Reads stream until null-terminator or EOS
static String FromStream(Stream *in, size_t max_chars = 5 * 1024 * 1024, bool stop_at_limit = false);
// Reads up to N chars from stream
static String FromStreamCount(Stream *in, size_t count);
// Creates a lowercased copy of the string
String Lower() const;
// Creates an uppercased copy of the string
String Upper() const;
// Extract N leftmost characters as a new string
String Left(size_t count) const;
// Extract up to N characters starting from given index
String Mid(size_t from, size_t count = -1) const;
// Extract N rightmost characters
String Right(size_t count) const;
// Extract leftmost part, separated by the given char; if no separator was
// found returns the whole string
String LeftSection(char separator, bool exclude_separator = true) const;
// Extract rightmost part, separated by the given char; if no separator was
// found returns the whole string
String RightSection(char separator, bool exclude_separator = true) const;
// Extract the range of Xth to Yth fields, separated by the given character
String Section(char separator, size_t first, size_t last,
bool exclude_first_sep = true, bool exclude_last_sep = true) const;
// Splits the string into segments divided by the instances of a given character,
// including empty segments e.g. if separators follow each other;
// returns at least one segment (equal to full string if no separator was found)
std::vector<String> Split(char separator) const;
//-------------------------------------------------------------------------
// String modification methods
//-------------------------------------------------------------------------
// Ensure string has at least space to store N chars;
// this does not change string contents, nor length
void Reserve(size_t max_length);
// Ensure string has at least space to store N additional chars
void ReserveMore(size_t more_length);
// Make string's buffer as small as possible to hold current data
void Compact();
// Append* methods add content at the string's end, increasing its length
// Appends another string to this string
void Append(const String &str);
void Append(const char *cstr) {
String str = String::Wrapper(cstr);
Append(str);
}
void Append(const char *cstr, size_t len);
// Appends a single character
void AppendChar(char c);
// Appends a formatted string
void AppendFmt(MSVC_PRINTF const char *fcstr, ...) GCC_PRINTF(2, 3);
void AppendFmtv(const char *fcstr, va_list argptr);
// Clip* methods decrease the string, removing defined part
// Cuts off leftmost N characters
void ClipLeft(size_t count);
// Cuts out N characters starting from given index
void ClipMid(size_t from, size_t count = -1);
// Cuts off rightmost N characters
void ClipRight(size_t count);
// Cuts off leftmost part, separated by the given char; if no separator was
// found cuts whole string, leaving empty string
void ClipLeftSection(char separator, bool include_separator = true);
// Cuts off rightmost part, separated by the given char; if no separator
// was found cuts whole string, leaving empty string
void ClipRightSection(char separator, bool include_separator = true);
// Cuts out the range of Xth to Yth fields separated by the given character
void ClipSection(char separator, size_t first, size_t last,
bool include_first_sep = true, bool include_last_sep = true);
// Sets string length to zero
void Empty();
// Makes a new string by filling N chars with certain value
void FillString(char c, size_t count);
// Makes a new string by putting in parameters according to format string
void Format(const char *fcstr, ...);
void FormatV(const char *fcstr, va_list argptr);
// Decrement ref counter and deallocate data if must.
// Free() should be called only when buffer is not needed anymore;
// if string must be truncated to zero length, but retain the allocated
// memory, call Empty() instead.
void Free();
// Convert string to lowercase equivalent
void MakeLower();
// Convert string to uppercase equivalent
void MakeUpper();
// Merges sequences of same characters into one
void MergeSequences(char c = 0);
// Prepend* methods add content before the string's head, increasing its length
// Prepends another string to this string
void Prepend(const String &str);
void Prepend(const char *cstr) {
String str = String::Wrapper(cstr); Prepend(str);
}
// Prepends a single character
void PrependChar(char c);
// Replaces all occurrences of one character with another character
void Replace(char what, char with);
// Replaces all occurrences of one substring with another substring
void Replace(const String &what, const String &with);
void Replace(const char *what, const char *with) {
String whats = String::Wrapper(what), withs = String::Wrapper(with); Replace(whats, withs);
}
// Replaces particular substring with another substring; new substring
// may have different length
void ReplaceMid(size_t from, size_t count, const String &str);
void ReplaceMid(size_t from, size_t count, const char *cstr) {
String str = String::Wrapper(cstr); ReplaceMid(from, count, str);
}
// Reverses the string
void Reverse();
// Reverse the multibyte unicode string
// FIXME: name? invent some consistent naming for necessary multibyte funcs,
// proper utf8 support where necessary
void ReverseUTF8();
// Overwrite the Nth character of the string; does not change string's length
void SetAt(size_t index, char c);
// Makes a new string by copying up to N chars from C-string
void SetString(const char *cstr, size_t length = -1);
// For all Trim functions, if given character value is 0, all whitespace
// characters (space, tabs, CRLF) are removed.
// Remove heading and trailing characters from the string
void Trim(char c = 0);
// Remove heading characters from the string;
void TrimLeft(char c = 0);
// Remove trailing characters from the string
void TrimRight(char c = 0);
// Truncate* methods decrease the string to the part of itself
// Truncate the string to the leftmost N characters
void TruncateToLeft(size_t count);
// Truncate the string to the middle N characters
void TruncateToMid(size_t from, size_t count = -1);
// Truncate the string to the rightmost N characters
void TruncateToRight(size_t count);
// Truncate the string to the leftmost part, separated by the given char;
// if no separator was found leaves string unchanged
void TruncateToLeftSection(char separator, bool exclude_separator = true);
// Truncate the string to the rightmost part, separated by the given char;
// if no separator was found leaves string unchanged
void TruncateToRightSection(char separator, bool exclude_separator = true);
// Truncate the string to range of Xth to Yth fields separated by the
// given character
void TruncateToSection(char separator, size_t first, size_t last,
bool exclude_first_sep = true, bool exclude_last_sep = true);
// Wraps the given string buffer without owning it, won't count references,
// won't delete it at destruction. Can be used with string literals.
void Wrap(const char *cstr);
//-------------------------------------------------------------------------
// Operators
//-------------------------------------------------------------------------
// Assign String by sharing data reference
String &operator=(const String &str);
// Move operator
String &operator=(String &&str);
// Assign C-string by copying contents
String &operator=(const char *cstr);
inline char operator[](size_t index) const {
assert(index < _len);
return _cstr[index];
}
inline bool operator ==(const String &str) const {
return Compare(str) == 0;
}
inline bool operator ==(const char *cstr) const {
return Compare(cstr) == 0;
}
inline bool operator !=(const String &str) const {
return Compare(str) != 0;
}
inline bool operator !=(const char *cstr) const {
return Compare(cstr) != 0;
}
inline bool operator <(const String &str) const {
return Compare(str) < 0;
}
inline bool operator <(const char *cstr) const {
return Compare(cstr) < 0;
}
// Converts an AGS string to a ScummVM one
operator Common::String() const {
return Common::String(_cstr);
}
// Fixes compilation error in script_set
operator bool() const {
return !IsEmpty();
}
operator const char *() const {
return GetCStr();
}
private:
// Creates new empty string with buffer enough to fit given length
void Create(size_t buffer_length);
// Release string and copy data to the new buffer
void Copy(size_t buffer_length, size_t offset = 0);
// Aligns data at given offset
void Align(size_t offset);
// Tells if this object shares its string buffer with others
bool IsShared() const;
// Ensure this string is a writeable independent copy, with ref counter = 1
void BecomeUnique();
// Ensure this string is independent, and there's enough space before
// or after the current string data
void ReserveAndShift(bool left, size_t more_length);
// Internal String data
char *_cstr; // pointer to actual string data; always valid, never null
size_t _len; // valid string length, in characters, excluding null-term
// Header of a reference-counted buffer
struct BufHeader {
size_t RefCount = 0; // reference count
size_t Capacity = 0; // available space, in characters
};
// Union that groups mutually exclusive data (currently only ref counted buffer)
union {
char *_buf; // reference-counted data (raw ptr)
BufHeader *_bufHead; // the header of a reference-counted data
};
};
} // namespace Shared
} // namespace AGS
} // namespace AGS3
#endif
|