1
0
mirror of https://github.com/stefanocasazza/ULib.git synced 2025-09-28 19:05:55 +08:00
ULib/include/ulib/string.h
stefanocasazza 6f299d2ccb sync
2018-05-21 15:57:13 +02:00

2650 lines
74 KiB
C++

// ============================================================================
//
// = LIBRARY
// ULib - c++ library
//
// = FILENAME
// string.h - Components for manipulating sequences of characters
//
// = AUTHOR
// Stefano Casazza
//
// ============================================================================
#ifndef ULIB_USTRING_H
#define ULIB_USTRING_H 1
#include <ulib/base/hash.h>
#include <ulib/internal/common.h>
#include <ulib/base/utility.h>
enum StringAllocationType {
STR_ALLOCATE_SOAP = 0x00000001,
STR_ALLOCATE_IMAP = 0x00000002,
STR_ALLOCATE_SSI = 0x00000004,
STR_ALLOCATE_NOCAT = 0x00000008,
STR_ALLOCATE_HTTP = 0x00000010,
STR_ALLOCATE_QUERY_PARSER = 0x00000020,
STR_ALLOCATE_ORM = 0x00000040,
STR_ALLOCATE_HTTP2 = 0x00000080
};
enum StringAllocationIndex {
STR_ALLOCATE_INDEX_SOAP = 20,
STR_ALLOCATE_INDEX_IMAP = STR_ALLOCATE_INDEX_SOAP+14,
STR_ALLOCATE_INDEX_SSI = STR_ALLOCATE_INDEX_IMAP+4,
STR_ALLOCATE_INDEX_NOCAT = STR_ALLOCATE_INDEX_SSI+2,
STR_ALLOCATE_INDEX_HTTP = STR_ALLOCATE_INDEX_NOCAT+2,
STR_ALLOCATE_INDEX_QUERY_PARSER = STR_ALLOCATE_INDEX_HTTP+9,
STR_ALLOCATE_INDEX_ORM = STR_ALLOCATE_INDEX_QUERY_PARSER+5,
STR_ALLOCATE_INDEX_HTTP2 = STR_ALLOCATE_INDEX_ORM+15
};
// macro for constant string like "xxx"
#define U_STRING_RFIND(x,str) (x).rfind(str,U_NOT_FOUND,U_CONSTANT_SIZE(str)) // string constant
#define U_STRING_FIND(x,start,str) (x).find(str,(start),U_CONSTANT_SIZE(str)) // string constant
#define U_STRING_FIND_EXT(x,start,str,n) (x).find(str,(start),U_CONSTANT_SIZE(str),n) // string constant
#define U_STRING_FINDNOCASE_EXT(x,start,str,n) (x).findnocase(str,(start),U_CONSTANT_SIZE(str),n) // string constant
#define U_STRING_COPY(str) UString((void*)(str).data(),(str).size())
#define U_STRING_FROM_CONSTANT(str) UString(str,U_CONSTANT_SIZE(str)) // string constant
#define U_ENDS_WITH(x,str) u_endsWith((x).data(),(x).size(),U_CONSTANT_TO_PARAM(str)) // string constant
// UString content and size
#ifdef DEBUG_DEBUG
# define U_STRING_TO_TRACE(str) U_min(128,(str).size()),(str).data()
#else
# define U_STRING_TO_TRACE(str) (str).size(), (str).data()
#endif
#define U_STRING_TO_PARAM(str) (str).data(), (str).size()
#define U_STRING_TO_RANGE(str) (str).data(), (str).pend()
/**
* UStringRep: string representation
* ---------------------------------------------------------------------------------------------------------
* The string object requires only one allocation. The allocation function which gets a block of raw bytes
* and with room enough and constructs a UStringRep object at the front. Invariants:
* ---------------------------------------------------------------------------------------------------------
* 1. string really contains length+1 characters; last is set to '\0' for sure on call to c_str()
* 2. capacity >= length - allocated memory is always capacity+1
* 3. references has two states:
* 0: one reference
* n>0: n+1 references
* 4. all fields == 0 is an empty string, given the extra storage beyond-the-end for a null terminator;
* thus, the shared empty string representation needs no constructor
* ---------------------------------------------------------------------------------------------------------
* Note that the UStringRep object is a POD so that you can have a static "empty string" UStringRep object
* already "constructed" before static constructors have run. The reference-count encoding is chosen so that
* a 0 indicates 1 reference, so you never try to destroy the empty-string UStringRep object
*/
#ifdef DEBUG
# define U_STRINGREP_FROM_CONSTANT(cstr) (void*)U_CHECK_MEMORY_SENTINEL, U_NULLPTR, 0, U_CONSTANT_SIZE(cstr), 0, 0, cstr
#elif defined(U_SUBSTR_INC_REF)
# define U_STRINGREP_FROM_CONSTANT(cstr) U_NULLPTR, U_CONSTANT_SIZE(cstr), 0, 0, cstr
#else
# define U_STRINGREP_FROM_CONSTANT(cstr) U_CONSTANT_SIZE(cstr), 0, 0, cstr
#endif
class Url;
class UCDB;
class URDB;
class UTDB;
class UFile;
class UDES3;
class UHTTP;
class UHTTP2;
class UValue;
class UCache;
class UValue;
class UString;
class UBase64;
class UEscape;
class UHexDump;
class UOptions;
class UTimeDate;
class UStringExt;
class USocketExt;
class UOrmDriver;
class UXMLEscape;
class UMimeHeader;
class UPop3Client;
class UHttpPlugIn;
class UProxyPlugIn;
class Application;
class UFlatBuffer;
class UServer_Base;
class UHashMapNode;
class UHashTableNode;
class UMongoDBClient;
class URDBClient_Base;
class UQuotedPrintable;
class UClientImage_Base;
class UREDISClient_Base;
template <class T> class UVector;
template <class T> class UHashMap;
template <class T> class UHashTable;
template <class T> class UJsonTypeHandler;
typedef void (*vPFprpv)(UStringRep*,void*);
typedef bool (*bPFprpv)(UStringRep*,void*);
class U_EXPORT UStringRep {
public:
// Check for memory error
U_MEMORY_TEST
// Allocator e Deallocator
U_MEMORY_ALLOCATOR
U_MEMORY_DEALLOCATOR
// --------------------------
// references has two states:
// --------------------------
// 0: one reference
// n>0: n+1 references
// --------------------------
bool uniq() const
{
U_TRACE_NO_PARAM(0, "UStringRep::uniq()")
U_CHECK_MEMORY
if (references == 0) U_RETURN(true); // NB: 0 -> one reference
U_RETURN(false);
}
void hold()
{
U_TRACE_NO_PARAM(0, "UStringRep::hold()")
U_CHECK_MEMORY
U_INTERNAL_DUMP("this = %p parent = %p references = %d child = %d", this, parent, references, child)
++references;
}
void release() // NB: we don't use delete (dtor) because add a deallocation to the destroy object process...
{
U_TRACE_NO_PARAM(0, "UStringRep::release()")
U_INTERNAL_DUMP("this = %p parent = %p references = %u child = %d", this, parent, references, child)
# ifdef DEBUG
if (memory.invariant() == false)
{
U_ERROR("UStringRep::release() %s - this = %p parent = %p references = %u child = %d _capacity = %u str(%u) = %.*S",
memory.getErrorType(this), this, parent, references, child, _capacity, _length, _length, str);
}
# endif
if (references) --references;
else _release();
}
// Size and Capacity
uint32_t size() const { return _length; }
uint32_t length() const { return _length; }
bool empty() const
{
U_TRACE_NO_PARAM(0, "UStringRep::empty()")
U_CHECK_MEMORY
U_RETURN(_length == 0);
}
uint32_t capacity() const
{
U_TRACE_NO_PARAM(0, "UStringRep::capacity()")
U_CHECK_MEMORY
U_RETURN(_capacity);
}
bool writeable() const
{
U_TRACE_NO_PARAM(0, "UStringRep::writeable()")
U_CHECK_MEMORY
U_RETURN(_capacity != 0); // mode: 0 -> const
}
bool isNullTerminated() const { return (str [_length] == '\0'); }
void setNullTerminated() const { ((char*)str)[_length] = '\0'; }
uint32_t space() const
{
U_TRACE_NO_PARAM(0, "UStringRep::space()")
U_CHECK_MEMORY
if ((int32_t)_capacity > 0) U_RETURN(_capacity - _length);
U_RETURN(0);
}
ptrdiff_t remain(const char* ptr) const
{
U_TRACE(0, "UStringRep::remain(%p)", ptr)
U_CHECK_MEMORY
U_INTERNAL_ASSERT((str + ((int32_t)_capacity > 0 ? _capacity : _length)) >= ptr)
U_RETURN((str + _length) - ptr);
}
uint32_t distance(const char* ptr) const
{
U_TRACE(0, "UStringRep::distance(%p)", ptr)
U_CHECK_MEMORY
U_INTERNAL_ASSERT((str + ((int32_t)_capacity > 0 ? _capacity : _length)) >= ptr)
U_RETURN(ptr - str);
}
uint32_t fold(uint32_t pos, uint32_t off) const { return fold(pos, off, _length); }
// C-Style String
char* data() const { return (char*)str; }
uint32_t copy(char* s, uint32_t n = U_NOT_FOUND, uint32_t pos = 0) const;
// ELEMENT ACCESS
char at(uint32_t pos) const
{
U_TRACE(0, "UStringRep::at(%u)", pos)
U_CHECK_MEMORY
U_INTERNAL_ASSERT_MINOR(pos, _length)
U_RETURN(str[pos]);
}
char first_char() const
{
U_TRACE_NO_PARAM(0, "UStringRep::first_char()")
U_CHECK_MEMORY
U_INTERNAL_ASSERT_MAJOR(_length, 0)
U_RETURN(str[0]);
}
char last_char() const
{
U_TRACE_NO_PARAM(0, "UStringRep::last_char()")
U_CHECK_MEMORY
U_INTERNAL_ASSERT_MAJOR(_length, 0)
U_RETURN(str[_length - 1]);
}
void setLastChar(char c)
{
U_TRACE(0, "UStringRep::setLastChar(%C)", c)
U_CHECK_MEMORY
U_INTERNAL_ASSERT_MAJOR(_length, 0)
((char*)str)[_length - 1] = c;
}
char operator[](uint32_t pos) const { return str[pos]; }
const char* c_pointer(uint32_t pos) const { return (str + pos); }
char* pend() const { return (char*)(str + _length); }
// Compare
int compare(const char* s, uint32_t n) const
{
U_TRACE(0, "UStringRep::compare(%.*S,%u)", n, s, n)
U_CHECK_MEMORY
int r = memcmp(str, s, U_min(_length, n));
U_INTERNAL_DUMP("str = %.*S", U_min(_length, n), str)
if (r == 0) r = (_length - n);
U_RETURN(r);
}
int compare(const UStringRep* rep) const { return compare(rep->str, rep->_length); }
int compare(uint32_t pos, uint32_t n1, const char* s, uint32_t n2) const
{
U_TRACE(0, "UStringRep::compare(%u,%u,%.*S,%u)", pos, n1, n2, s, n2)
U_CHECK_MEMORY
U_INTERNAL_ASSERT((pos + n1) <= _length)
int r = memcmp(str + pos, s, U_min(n1, n2));
if (r == 0) r = (n1 - n2);
U_RETURN(r);
}
int compare(const UStringRep* rep, uint32_t depth) const __pure;
// Compare with ignore case
int comparenocase(const char* s, uint32_t n) const
{
U_TRACE(0, "UStringRep::comparenocase(%.*S,%u)", n, s, n)
U_CHECK_MEMORY
int r = u__strncasecmp(str, s, U_min(_length, n));
U_INTERNAL_DUMP("str = %.*S", U_min(_length, n), str)
if (r == 0) r = (_length - n);
U_RETURN(r);
}
int comparenocase(const UStringRep* rep) const { return comparenocase(rep->str, rep->_length); }
// Equal
bool equal(char c) const
{
U_TRACE(0, "UStringRep::equal(%C)", c)
U_CHECK_MEMORY
if (*str == c &&
_length == 1)
{
U_RETURN(true);
}
U_RETURN(false);
}
bool equal(const char* s, uint32_t n) const
{
U_TRACE(0, "UStringRep::equal(%#.*S,%u)", n, s, n)
U_CHECK_MEMORY
U_INTERNAL_ASSERT_POINTER(s)
if (_length == n &&
memcmp(str, s, n) == 0)
{
U_RETURN(true);
}
U_RETURN(false);
}
bool equal(const UStringRep* rep) const { return equal(rep->str, rep->_length); }
// Equal with ignore case
bool equalnocase(char c) const
{
U_TRACE(0, "UStringRep::equalnocase(%C)", c)
U_CHECK_MEMORY
if (_length == 1 &&
u__tolower(*str) == u__tolower(c))
{
U_RETURN(true);
}
U_RETURN(false);
}
bool equalnocase(const char* s, uint32_t n) const
{
U_TRACE(0, "UStringRep::equalnocase(%.*S,%u)", n, s, n)
U_CHECK_MEMORY
U_INTERNAL_ASSERT_POINTER(s)
if (_length == n &&
u__strncasecmp(str, s, n) == 0)
{
U_RETURN(true);
}
U_RETURN(false);
}
bool equalnocase(const UStringRep* rep) const { return equalnocase(rep->str, rep->_length); }
// Substring
bool isSubStringOf(UStringRep* rep) const __pure;
UStringRep* substr(const char* t, uint32_t tlen) const;
UStringRep* substr(uint32_t pos, uint32_t n) const { return substr(str + pos, n); }
// Assignment
void size_adjust()
{
U_TRACE_NO_PARAM(0+256, "UStringRep::size_adjust()")
U_CHECK_MEMORY
U_INTERNAL_ASSERT_MAJOR(_capacity, 0)
# ifdef DEBUG
if (references)
{
string_rep_share = this;
U_DUMP_OBJECT_WITH_CHECK("shared with this", checkIfReferences)
U_INTERNAL_ASSERT_MSG(false, "CANNOT ADJUST SIZE OF A REFERENCED STRING...")
}
# endif
_length = u__strlen(str, __PRETTY_FUNCTION__);
U_INTERNAL_ASSERT(invariant())
}
void size_adjust(uint32_t value)
{
U_TRACE(0+256, "UStringRep::size_adjust(%u)", value)
U_CHECK_MEMORY
U_INTERNAL_ASSERT_MAJOR((int32_t)_capacity, 0)
# ifdef DEBUG
if (references)
{
string_rep_share = this;
U_DUMP_OBJECT_WITH_CHECK("shared with this", checkIfReferences)
U_INTERNAL_ASSERT_MSG(false, "CANNOT ADJUST SIZE OF A REFERENCED STRING...")
}
# endif
U_INTERNAL_ASSERT(value <= _capacity)
((char*)str)[_length = value] = '\0';
U_INTERNAL_ASSERT(invariant())
}
void size_adjust_force()
{
U_TRACE_NO_PARAM(0, "UStringRep::size_adjust_force()")
U_CHECK_MEMORY
U_INTERNAL_ASSERT_MAJOR((int32_t)_capacity, 0)
_length = u__strlen(str, __PRETTY_FUNCTION__);
U_INTERNAL_ASSERT(invariant())
}
void size_adjust_force(uint32_t value)
{
U_TRACE(0, "UStringRep::size_adjust_force(%u)", value)
U_CHECK_MEMORY
U_INTERNAL_ASSERT(value <= _capacity)
U_INTERNAL_ASSERT_MAJOR((int32_t)_capacity, 0)
((char*)str)[_length = value] = '\0';
U_INTERNAL_ASSERT(invariant())
}
void size_adjust( const char* ptr) { size_adjust( distance(ptr)); }
void size_adjust_force(const char* ptr) { size_adjust_force(distance(ptr)); }
void replace(const char* s, uint32_t n)
{
U_TRACE(0, "UStringRep::replace(%S,%u)", s, n)
U_INTERNAL_ASSERT_MAJOR(n, 0)
U_INTERNAL_ASSERT(_capacity >= n)
U_MEMCPY((char*)str, s, n);
((char*)str)[(_length = n)] = '\0';
}
#ifdef DEBUG
bool invariant() const;
const char* dump(bool reset) const;
#endif
// EXTENSION
bool isBinary(uint32_t pos) const
{
U_TRACE(0, "UStringRep::isBinary(%u)", pos)
U_CHECK_MEMORY
U_INTERNAL_ASSERT_MINOR(pos, _length)
if (u_isBinary((const unsigned char*)(str + pos), _length - pos)) U_RETURN(true);
U_RETURN(false);
}
bool isBase64(uint32_t pos) const
{
U_TRACE(0, "UStringRep::isBase64(%u)", pos)
U_CHECK_MEMORY
if (_length)
{
U_INTERNAL_ASSERT_MINOR(pos, _length)
if (u_isBase64(str + pos, _length - pos)) U_RETURN(true);
}
U_RETURN(false);
}
bool isBase64Url(uint32_t pos) const
{
U_TRACE(0, "UStringRep::isBase64Url(%u)", pos)
U_CHECK_MEMORY
if (_length)
{
U_INTERNAL_ASSERT_MINOR(pos, _length)
if (u_isBase64Url(str + pos, _length - pos)) U_RETURN(true);
}
U_RETURN(false);
}
bool isPrintable(uint32_t pos, bool bline = false) const
{
U_TRACE(0, "UStringRep::isPrintable(%u,%b)", pos, bline)
U_CHECK_MEMORY
if (_length)
{
U_INTERNAL_ASSERT_MINOR(pos, _length)
if (u_isPrintable(str + pos, _length - pos, bline)) U_RETURN(true);
}
U_RETURN(false);
}
bool isWhiteSpace(uint32_t pos) const
{
U_TRACE(0, "UStringRep::isWhiteSpace(%u)", pos)
U_CHECK_MEMORY
if (_length)
{
U_INTERNAL_ASSERT_MINOR(pos, _length)
if (u_isWhiteSpace(str + pos, _length - pos) == false) U_RETURN(false);
}
U_RETURN(true);
}
bool isText(uint32_t pos) const
{
U_TRACE(0, "UStringRep::isText(%u)", pos)
U_CHECK_MEMORY
if (_length)
{
U_INTERNAL_ASSERT_MINOR(pos, _length)
if (u_isText((const unsigned char*)(str + pos), _length - pos)) U_RETURN(true);
}
U_RETURN(false);
}
bool isUTF8(uint32_t pos) const
{
U_TRACE(0, "UStringRep::isUTF8(%u)", pos)
U_CHECK_MEMORY
U_INTERNAL_ASSERT_MINOR(pos, _length)
if (u_isUTF8((const unsigned char*)(str + pos), _length - pos)) U_RETURN(true);
U_RETURN(false);
}
bool isUTF16(uint32_t pos) const
{
U_TRACE(0, "UStringRep::isUTF16(%u)", pos)
U_CHECK_MEMORY
U_INTERNAL_ASSERT_MINOR(pos, _length)
if (u_isUTF16((const unsigned char*)(str + pos), _length - pos)) U_RETURN(true);
U_RETURN(false);
}
bool isXMacAddr() const
{
U_TRACE_NO_PARAM(0, "UStringRep::isXMacAddr()")
U_CHECK_MEMORY
if (u_isXMacAddr(str, _length)) U_RETURN(true);
U_RETURN(false);
}
bool isEndHeader(uint32_t pos) const __pure;
bool findEndHeader(uint32_t pos) const __pure
{
U_TRACE(0, "UStringRep::findEndHeader(%u)", pos)
U_CHECK_MEMORY
if (_length)
{
U_INTERNAL_ASSERT_MINOR(pos, _length)
if (u_findEndHeader1(str + pos, _length - pos) != U_NOT_FOUND) U_RETURN(true); // find sequence of U_CRLF2
}
U_RETURN(false);
}
uint32_t findWhiteSpace(uint32_t pos) const __pure
{
U_TRACE(0, "UStringRep::findWhiteSpace(%u)", pos)
U_CHECK_MEMORY
U_INTERNAL_ASSERT(pos <= _length)
for (; pos < _length; ++pos)
{
if (u__isspace(str[pos])) U_RETURN(pos);
}
U_RETURN(U_NOT_FOUND);
}
#ifdef HAVE_STRTOF
float strtof() const;
#endif
#ifdef HAVE_STRTOLD
long double strtold() const; // long double
#endif
bool strtob() const __pure;
int64_t strtoll( bool check_for_suffix = false) const __pure;
uint64_t strtoull(bool check_for_suffix = false) const __pure;
long strtol( bool check_for_suffix = false) const __pure;
unsigned long strtoul(bool check_for_suffix = false) const __pure;
uint32_t hash() const
{
U_TRACE_NO_PARAM(0, "UStringRep::hash()")
U_CHECK_MEMORY
uint32_t result = u_hash((const unsigned char*)str, _length);
U_INTERNAL_ASSERT_MAJOR(result, 0)
U_RETURN(result);
}
uint32_t hashIgnoreCase() const
{
U_TRACE_NO_PARAM(0, "UStringRep::hashIgnoreCase()")
U_CHECK_MEMORY
uint32_t result = u_hash_ignore_case((const unsigned char*)str, _length);
U_INTERNAL_ASSERT_MAJOR(result, 0)
U_RETURN(result);
}
// for constant string
void trim();
// if the string is quoted...
bool isQuoted(const unsigned char c) const
{
U_TRACE(0, "UStringRep::isQuoted(%C)", c)
U_CHECK_MEMORY
if (str[0] == c &&
str[_length-1] == c)
{
U_RETURN(true);
}
U_RETURN(false);
}
// ...unquote it
void unQuote()
{
U_TRACE_NO_PARAM(0, "UStringRep::unQuote()")
U_CHECK_MEMORY
U_INTERNAL_ASSERT_MAJOR(_length, 2)
U_INTERNAL_ASSERT_EQUALS((int32_t)_capacity, 0)
++str;
_length -= 2;
}
static bool needQuote(const char* s, uint32_t n)
{
U_TRACE(0, "UStringRep::needQuote(%S,%u)", s, n)
U_INTERNAL_ASSERT_MAJOR(n, 0)
for (const char* _end = s + n; s < _end; ++s)
{
char c = *s;
if (c == '"' ||
c == '\\' ||
u__isspace(c))
{
U_RETURN(true);
}
}
U_RETURN(false);
}
bool needQuote() const
{
U_TRACE_NO_PARAM(0, "UStringRep::needQuote()")
U_CHECK_MEMORY
if (_length == 0) U_RETURN(true);
return needQuote(str, _length);
}
uint32_t getSpaceToDump() const
{
U_TRACE_NO_PARAM(0, "UStringRep::getSpaceToDump()")
U_CHECK_MEMORY
if (needQuote() == false) U_RETURN(_length);
uint32_t sz = _length + U_CONSTANT_SIZE("");
U_RETURN(sz);
}
static uint32_t fold(uint32_t pos, uint32_t off, uint32_t sz)
{
U_TRACE(0, "UStringRep::fold(%u,%u,%u)", pos, off, sz)
uint32_t dist = (sz - pos),
newoff = (off < dist ? off : dist);
U_RETURN(newoff);
}
// UTF8 <--> ISO Latin 1
static UStringRep* toUTF8(const unsigned char* t, uint32_t tlen);
static UStringRep* fromUTF8(const unsigned char* t, uint32_t tlen);
static uint32_t max_size() { return U_STRING_MAX_SIZE; } // The maximum number of individual char elements of an individual string is determined by max_size()
static UStringRep* create(uint32_t length, uint32_t capacity, const char* ptr); // NB: we don't use new (ctor) because we want an allocation with more space for string data...
static UStringRep* string_rep_null; // This storage is init'd to 0 by the linker, resulting (carefully) in an empty string with one(=>0) reference...
#if defined(U_SUBSTR_INC_REF) || defined(DEBUG)
UStringRep* parent; // manage substring to increment reference of source string
# ifdef DEBUG
int32_t child; // manage substring to capture event 'DEAD OF SOURCE STRING WITH CHILD ALIVE'...
static bool check_dead_of_source_string_with_child_alive;
# endif
#endif
// STREAM
#ifdef U_STDCPP_ENABLE
void write(ostream& os) const;
friend ostream& operator<<(ostream& os, const UStringRep& r) { r.write(os); return os; }
#endif
protected:
uint32_t _length,
_capacity, // [0 const | -1 mmap]...
references; // NB: must be here, see string_rep_null...
const char* str;
// ----------------> maybe unnamed array of char...
#ifdef DEBUG
static int32_t max_child;
static UStringRep* parent_destroy;
static UStringRep* string_rep_share;
static bool checkIfChild( const char* name_class, void* ptr_object);
static bool checkIfReferences(const char* name_class, void* ptr_object);
#endif
private:
void set(uint32_t __length, uint32_t __capacity, const char* ptr)
{
U_TRACE(0, "UStringRep::set(%u,%u,%p)", __length, __capacity, ptr)
U_CHECK_MEMORY
U_INTERNAL_ASSERT_POINTER(ptr)
# if defined(U_SUBSTR_INC_REF) || defined(DEBUG)
parent = U_NULLPTR;
# ifdef DEBUG
child = 0;
# endif
# endif
_length = __length;
_capacity = __capacity; // [0 const | -1 mmap | -2 we must call free()]...
references = 0;
str = ptr;
}
explicit UStringRep(const char* t, uint32_t tlen) // NB: to use only with new(UStringRep(t,tlen))...
{
U_TRACE_CTOR(0, UStringRep, "%p,%u", t, tlen)
U_INTERNAL_ASSERT_POINTER(t)
U_INTERNAL_ASSERT_MAJOR(tlen, 0)
set(tlen, 0U, t);
}
~UStringRep();
void _release();
void shift(ptrdiff_t diff)
{
U_TRACE(0, "UStringRep::shift(%p)", diff)
U_CHECK_MEMORY
U_INTERNAL_ASSERT_DIFFERS(diff, 0)
U_INTERNAL_ASSERT_EQUALS(_capacity, 0) // mode: 0 -> const
U_INTERNAL_DUMP("this = %V", this)
str += diff;
U_INTERNAL_DUMP("this = %V", this)
U_INTERNAL_ASSERT_DIFFERS(str[0], 0)
U_INTERNAL_ASSERT(invariant())
}
UStringRep* duplicate() const
{
U_TRACE_NO_PARAM(0, "UStringRep::duplicate()")
U_INTERNAL_ASSERT_MAJOR(_length, 0)
U_INTERNAL_ASSERT_EQUALS(_capacity, 0) // mode: 0 -> const
return UStringRep::create(_length, _length, str);
}
// equal lookup use case
static bool equal_lookup(UStringRep* key1, const char* s2, uint32_t n2, bool ignore_case)
{
U_TRACE(0, "UStringRep::equal_lookup(%V,%.*S,%u,%b)", key1, n2, s2, n2, ignore_case)
U_INTERNAL_ASSERT_POINTER(s2)
U_INTERNAL_ASSERT_MAJOR(n2, 0)
U_INTERNAL_ASSERT_POINTER(key1)
const char* s1;
uint32_t n1 = key1->size();
U_INTERNAL_ASSERT_MAJOR(n1, 0)
if (n1 == n2 &&
((s1 = key1->data(), memcmp(s1, s2, n1) == 0) ||
(ignore_case && u__strncasecmp(s1, s2, n1) == 0)))
{
U_RETURN(true);
}
U_RETURN(false);
}
static bool equal_lookup(const UStringRep* key1, const UStringRep* key2, bool ignore_case)
{
U_TRACE(0, "UStringRep::equal_lookup(%V,%V,%b)", key1, key2, ignore_case)
U_INTERNAL_ASSERT_POINTER(key1)
U_INTERNAL_ASSERT_POINTER(key2)
const char* s1;
const char* s2;
uint32_t n1 = key1->size(),
n2 = key2->size();
U_INTERNAL_ASSERT_MAJOR(n1, 0)
U_INTERNAL_ASSERT_MAJOR(n2, 0)
if ( n1 == n2 &&
(key1 == key2 ||
(s1 = key1->data(),
s2 = key2->data(), memcmp(s1, s2, n1) == 0) ||
(ignore_case && u__strncasecmp(s1, s2, n1) == 0)))
{
U_RETURN(true);
}
U_RETURN(false);
}
U_DISALLOW_COPY_AND_ASSIGN(UStringRep)
friend class Url;
friend class ULib;
friend class UCDB;
friend class URDB;
friend class UTDB;
friend class UDES3;
friend class UHTTP;
friend class UHTTP2;
friend class UCache;
friend class UValue;
friend class UString;
friend class UBase64;
friend class UEscape;
friend class UHexDump;
friend class UOptions;
friend class UTimeDate;
friend class UStringExt;
friend class USocketExt;
friend class UOrmDriver;
friend class UXMLEscape;
friend class UPop3Client;
friend class UMimeHeader;
friend class UHttpPlugIn;
friend class Application;
friend class UFlatBuffer;
friend class UProxyPlugIn;
friend class UHashMapNode;
friend class UServer_Base;
friend class UHashTableNode;
friend class UMongoDBClient;
friend class URDBClient_Base;
friend class UQuotedPrintable;
friend class UClientImage_Base;
friend class UREDISClient_Base;
friend struct UObjectIO;
template <class T> friend class UVector;
template <class T> friend class UHashMap;
template <class T> friend class UHashTable;
template <class T> friend class UJsonTypeHandler;
template <class T> friend void u_construct(const T*, uint32_t);
};
class U_EXPORT UString {
public:
// Allocator e Deallocator
U_MEMORY_ALLOCATOR
U_MEMORY_DEALLOCATOR
static const UString* str_host;
static const UString* str_chunked;
static const UString* str_without_mac;
static const UString* str_localhost;
static const UString* str_http;
static const UString* str_msg_rfc;
static const UString* str_txt_plain;
static const UString* str_address;
static const UString* str_CLIENT_QUEUE_DIR;
static const UString* str_point;
static const UString* str_true;
static const UString* str_false;
static const UString* str_response;
static const UString* str_zero;
static const UString* str_nostat;
static const UString* str_tsa;
static const UString* str_soap;
static const UString* str_path_root;
static const UString* str_asterisk;
// SOAP
static const UString* str_ns;
static const UString* str_boolean;
static const UString* str_byte;
static const UString* str_unsignedByte;
static const UString* str_short;
static const UString* str_unsignedShort;
static const UString* str_int;
static const UString* str_unsignedInt;
static const UString* str_long;
static const UString* str_unsignedLong;
static const UString* str_float;
static const UString* str_double;
static const UString* str_string;
static const UString* str_base64Binary;
// IMAP
static const UString* str_recent;
static const UString* str_unseen;
static const UString* str_uidnext;
static const UString* str_uidvalidity;
// PROXY SERVICE
static const UString* str_FOLLOW_REDIRECTS;
static const UString* str_CLIENT_CERTIFICATE;
static const UString* str_REMOTE_ADDRESS_IP;
static const UString* str_WEBSOCKET;
// NOCAT
static const UString* str_without_label;
static const UString* str_allowed_members_default;
// SSI
static const UString* str_cgi;
static const UString* str_var;
// HTTP
static const UString* str_origin;
static const UString* str_ctype_tsa;
static const UString* str_ctype_txt;
static const UString* str_ctype_html;
static const UString* str_ctype_soap;
static const UString* str_ulib_header;
static const UString* str_storage_keyid;
static const UString* str_websocket_key;
static const UString* str_websocket_prot;
// QUERY PARSER
static const UString* str_p1;
static const UString* str_p2;
static const UString* str_or;
static const UString* str_and;
static const UString* str_not;
// ORM
static const UString* str_port;
static const UString* str_root;
static const UString* str_UTF8;
static const UString* str_UTF16;
static const UString* str_dbname;
static const UString* str_timeout;
static const UString* str_compress;
static const UString* str_character_set;
static const UString* str_auto_reconnect;
// ORM PGSQL
static const UString* str_pgsql_name;
static const UString* str_memory;
// ORM MYSQL
static const UString* str_mysql_name;
static const UString* str_secure_auth;
// ORM SQLITE
static const UString* str_sqlite_name;
static const UString* str_dbdir;
#ifndef U_HTTP2_DISABLE
static const UString* str_authority;
static const UString* str_method;
static const UString* str_method_get;
static const UString* str_method_post;
static const UString* str_path;
static const UString* str_path_index;
static const UString* str_scheme;
static const UString* str_scheme_https;
static const UString* str_status;
static const UString* str_status_200;
static const UString* str_status_204;
static const UString* str_status_206;
static const UString* str_status_304;
static const UString* str_status_400;
static const UString* str_status_404;
static const UString* str_status_500;
static const UString* str_accept_charset;
static const UString* str_accept_encoding;
static const UString* str_accept_encoding_value;
static const UString* str_accept_language;
static const UString* str_accept_ranges;
static const UString* str_accept;
static const UString* str_access_control_allow_origin;
static const UString* str_age;
static const UString* str_allow;
static const UString* str_authorization;
static const UString* str_cache_control;
static const UString* str_content_disposition;
static const UString* str_content_encoding;
static const UString* str_content_language;
static const UString* str_content_length;
static const UString* str_content_location;
static const UString* str_content_range;
static const UString* str_content_type;
static const UString* str_cookie;
static const UString* str_date;
static const UString* str_etag;
static const UString* str_expect;
static const UString* str_expires;
static const UString* str_from;
static const UString* str_if_match;
static const UString* str_if_modified_since;
static const UString* str_if_none_match;
static const UString* str_if_range;
static const UString* str_if_unmodified_since;
static const UString* str_last_modified;
static const UString* str_link;
static const UString* str_location;
static const UString* str_max_forwards;
static const UString* str_proxy_authenticate;
static const UString* str_proxy_authorization;
static const UString* str_range;
static const UString* str_referer;
static const UString* str_refresh;
static const UString* str_retry_after;
static const UString* str_server;
static const UString* str_set_cookie;
static const UString* str_strict_transport_security;
static const UString* str_transfer_encoding;
static const UString* str_user_agent;
static const UString* str_vary;
static const UString* str_via;
static const UString* str_www_authenticate;
static const UString* str_ULib;
#endif
static void str_allocate(int which);
// u_buffer string (for container, etc...)
static UString& getUBuffer()
{
U_INTERNAL_ASSERT_EQUALS(u_buffer_len, 0)
return *string_u_buffer;
}
// null string (for container, etc...)
static UString& getStringNull()
{
U_INTERNAL_ASSERT_EQUALS((bool)*string_null, false)
return *string_null;
}
protected:
static UStringRep* pkey;
static UString* string_null;
static UString* string_u_buffer;
friend class ULib;
friend class UFile;
friend class UHTTP2;
friend class UValue;
friend class UServices;
friend class UStringExt;
friend class USocketExt;
friend class UClientImage_Base;
friend class UREDISClient_Base;
template <class T> friend class UVector;
template <class T> friend class UHashMap;
template <class T> friend class UHashTable;
explicit UString(UStringRep** pr) : rep(*pr) // NB: for toUTF8() and fromUTF8()...
{
U_TRACE_CTOR(0, UString, "%V", *pr)
}
explicit UString(uint32_t len, uint32_t sz, char* ptr);
explicit UString(unsigned char* t, uint32_t tlen, uint32_t need) // NB: for UHTTP2::CONTINUATION...
{
U_TRACE_CTOR(0, UString, "%.*S,%u,%u", tlen, t, tlen, need)
U_INTERNAL_ASSERT_POINTER(t)
U_INTERNAL_ASSERT_MAJOR(tlen, 0)
U_INTERNAL_ASSERT_MAJOR(need, tlen)
rep = UStringRep::create(tlen, need, (const char*)t);
U_INTERNAL_ASSERT(invariant())
}
void setFromData(const char** ptr, uint32_t sz, unsigned char delim);
// NB: for UStringExt::deflate()...
void setConstant(uint32_t sz);
void size_adjust_constant(uint32_t sz);
public:
// mutable
UStringRep* rep;
// SERVICES
char* data() const { return rep->data(); }
bool empty() const { return rep->empty(); }
operator bool() const { return (rep->_length != 0); }
uint32_t size() const { return rep->size(); }
uint32_t space() const { return rep->space(); }
uint32_t length() const { return rep->length(); }
uint32_t capacity() const { return rep->capacity(); }
static uint32_t max_size() { return U_STRING_MAX_SIZE; }
protected:
void _set(UStringRep* r) // in 'memory reference' distinction is made between set, copy, e assign...
{
U_TRACE(0, "UString::_set(%V)", r)
U_INTERNAL_ASSERT_POINTER(r)
U_INTERNAL_ASSERT_DIFFERS(rep, r)
rep->release(); // 1. release existing resource
rep = r; // 2. bind copy to self
U_CHECK_MEMORY_OBJECT(rep)
}
void _copy(UStringRep* r)
{
U_TRACE(0, "UString::_copy(%V)", r)
U_INTERNAL_ASSERT_POINTER(r)
rep = r; // bind copy to self
rep->hold();
U_CHECK_MEMORY_OBJECT(rep)
}
// SUBSTRING
UString(const UStringRep* _rep, const char* t, uint32_t tlen)
{
U_TRACE_CTOR(0, UString, "%V,%p,%u", _rep, t, tlen)
U_INTERNAL_ASSERT_MAJOR(tlen, 0)
rep = _rep->substr(t, tlen);
U_INTERNAL_ASSERT(invariant())
}
UString(const UStringRep* _rep, uint32_t pos, uint32_t n = U_NOT_FOUND)
{
U_TRACE_CTOR(0, UString, "%V,%u,%u", _rep, pos, n)
rep = _rep->substr(pos, _rep->fold(pos, n));
U_INTERNAL_ASSERT(invariant())
}
public:
static uint32_t _getReserveNeed(uint32_t need = U_CAPACITY * 2)
{
U_TRACE(0, "UString::_getReserveNeed(%u)", need)
if (need < U_CAPACITY) need = U_CAPACITY;
else if (need > U_CAPACITY)
{
if (need < 2*1024*1024) need = (need * 2) + (PAGESIZE * 2);
need += PAGESIZE; // NB: to avoid duplication on realloc...
}
U_RETURN(need);
}
uint32_t getReserveNeed(uint32_t n) { return _getReserveNeed(rep->_length + n); }
void _assign(UStringRep* r)
{
U_TRACE(0, "UString::_assign(%V)", r)
U_INTERNAL_ASSERT_POINTER(r)
// NB: it works also in the case of (rep == r)...
r->hold(); // 1. take a copy of new resource
rep->release(); // 2. release existing resource
rep = r; // 3. bind copy to self
U_CHECK_MEMORY_OBJECT(rep)
}
// constructors
UString() : rep(UStringRep::string_rep_null)
{
U_TRACE_CTOR(0, UString, "", 0)
rep->hold();
U_INTERNAL_ASSERT(invariant())
}
explicit UString(const UStringRep* r) : rep((UStringRep*)r)
{
U_TRACE_CTOR(0, UString, "%V", r)
rep->hold();
U_INTERNAL_ASSERT(invariant())
}
explicit UString(ustringrep* r)
{
U_TRACE_CTOR(0, UString, "%p", r)
# ifdef DEBUG
r->_this = (void*)U_CHECK_MEMORY_SENTINEL;
# endif
uustringrep u = { r };
_copy(u.p2);
U_INTERNAL_ASSERT(invariant())
}
explicit UString(const char* t, uint32_t tlen)
{
U_TRACE_CTOR(0, UString, "%.*S,%u", tlen, t, tlen)
U_INTERNAL_ASSERT_MAJOR(tlen, 0)
U_NEW(UStringRep, rep, UStringRep(t, tlen));
U_INTERNAL_ASSERT(invariant())
}
// NB: Avoid constructors with a single integer argument! Use the explicit keyword if you can't avoid them...
explicit UString(uint32_t n)
{
U_TRACE_CTOR(0, UString, "%u", n)
rep = UStringRep::create(0U, n, U_NULLPTR);
U_INTERNAL_ASSERT(invariant())
}
explicit UString(const char* t)
{
U_TRACE_CTOR(0, UString, "%S", t)
uint32_t len = (t ? u__strlen(t, __PRETTY_FUNCTION__) : 0);
if (len) U_NEW(UStringRep, rep, UStringRep(t, len))
else _copy(UStringRep::string_rep_null);
U_INTERNAL_ASSERT(invariant())
}
explicit UString(const void* t, uint32_t tlen)
{
U_TRACE_CTOR(0, UString, "%.*S,%u", tlen, (char*)t, tlen)
U_INTERNAL_ASSERT_POINTER(t)
U_INTERNAL_ASSERT_MAJOR(tlen, 0)
rep = UStringRep::create(tlen, tlen, (const char*)t);
U_INTERNAL_ASSERT(invariant())
}
explicit UString(uint32_t n, unsigned char c)
{
U_TRACE_CTOR(0, UString, "%u,%C", n, c)
rep = UStringRep::create(n, n, U_NULLPTR);
(void) memset((void*)rep->str, c, n);
U_INTERNAL_ASSERT(invariant())
}
explicit UString(uint32_t sz, const char* format, uint32_t fmt_size, ...) // ctor with var arg
{
U_TRACE_CTOR(0, UString, "%u,%.*S,%u", sz, fmt_size, format, fmt_size)
U_INTERNAL_ASSERT_POINTER(format)
va_list argp;
va_start(argp, fmt_size);
rep = UStringRep::create(0U, sz, U_NULLPTR);
rep->_length = u__vsnprintf(rep->data(), rep->_capacity+1, format, fmt_size, argp);
va_end(argp);
U_INTERNAL_ASSERT(invariant())
}
explicit UString(const UString& str, uint32_t pos, uint32_t n = U_NOT_FOUND)
{
U_TRACE_CTOR(0, UString, "%p,%u,%u", &str, pos, n)
U_INTERNAL_ASSERT(pos <= str.size())
uint32_t sz = str.rep->fold(pos, n);
if (sz) rep = UStringRep::create(sz, sz, str.rep->str + pos);
else _copy(UStringRep::string_rep_null);
U_INTERNAL_ASSERT(invariant())
}
// SUBSTRING
UString substr(const char* t, uint32_t tlen) const
{
U_TRACE(0, "UString::substr(%.*S,%u)", tlen, t, tlen)
if (tlen == 0) return *string_null;
UString result(rep, t, tlen);
U_RETURN_STRING(result);
}
UString substr(uint32_t pos, uint32_t n = U_NOT_FOUND) const
{
U_TRACE(0, "UString::substr(%u,%u)", pos, n)
U_INTERNAL_ASSERT(pos <= rep->_length)
return substr(rep->str + pos, rep->fold(pos, n));
}
bool isSubStringOf(const UString& str) const { return rep->isSubStringOf(str.rep); }
// destructor
~UString()
{
U_TRACE_DTOR(0, UString)
U_INTERNAL_ASSERT_POINTER(rep)
U_CHECK_MEMORY_OBJECT(rep)
U_INTERNAL_ASSERT_DIFFERS(this, string_u_buffer)
rep->release();
}
// ASSIGNMENT
UString(const UString& str) : rep(str.rep)
{
U_TRACE_CTOR(0, UString, "%p", &str)
rep->hold();
U_INTERNAL_ASSERT(invariant())
}
UString& operator=(const UString& str)
{
U_TRACE(0, "UString::operator=(%p)", &str)
_assign(str.rep);
return *this;
}
// swap
void swap(UString& str)
{
U_TRACE(0, "UString::swap(%p)", &str)
UStringRep* tmp = rep;
rep = str.rep;
str.rep = tmp;
}
static void swap(UString& lhs, UString& rhs) { lhs.swap(rhs); }
#ifdef U_COMPILER_RVALUE_REFS
UString& operator=(UString && str)
{
U_TRACE_NO_PARAM(0, "UString::operator=(move)")
swap(str);
return *this;
}
# if (!defined(__GNUC__) || GCC_VERSION_NUM > 50300) // GCC has problems dealing with move constructor, so turn the feature on for 5.3.1 and above, only
UString(UString && str)
{
U_TRACE_NO_PARAM(0, "UString::UString(move)")
// Move the value (including the allocated memory) from the first object to the second one, and leave the first one empty.
// It will not need the value anyway, because the only operation that will be executed on it is the destruction. We must
// leave it in the state where destructor can be safely called without causing any problems such as releasing the resources
// that were stolen and now owned by another object
rep = str.rep;
str.rep = UStringRep::string_rep_null;
UStringRep::string_rep_null->hold();
U_INTERNAL_DUMP("rep = %p", rep)
U_INTERNAL_ASSERT(invariant())
}
# endif
#endif
// Replace
UString& replace(uint32_t pos, uint32_t n1, uint32_t n2, char c) // NB: unsigned char conflict with a uint32_t at the same parameter position...
{
U_TRACE(0, "UString::replace(%u,%u,%u,%C)", pos, n1, n2, c)
char* ptr = __replace(pos, n1, n2);
if (ptr && n2) (void) U_SYSCALL(memset, "%p,%d,%u", ptr, c, n2);
U_INTERNAL_ASSERT(invariant())
return *this;
}
UString& replace(uint32_t pos, uint32_t n1, const char* s, uint32_t n2)
{
U_TRACE(0, "UString::replace(%u,%u,%S,%u)", pos, n1, s, n2)
char* ptr = __replace(pos, n1, n2);
if (ptr && n2) U_MEMCPY(ptr, s, n2);
U_INTERNAL_ASSERT(invariant())
return *this;
}
UString& replace(uint32_t pos1, uint32_t n1, const UString& str, uint32_t pos2, uint32_t n2 = U_NOT_FOUND)
{
U_TRACE(0, "UString::replace(%u,%u,%p,%u,%u)", pos1, n1, &str, pos2, n2)
U_INTERNAL_ASSERT(pos2 <= str.size())
return replace(pos1, n1, str.data() + pos2, str.rep->fold(pos2, n2));
}
UString& replace(const char* s) { return replace(0U, size(), s, u__strlen(s, __PRETTY_FUNCTION__)); }
UString& replace(unsigned char c) { return replace(0U, size(), 1U, c); }
UString& replace(const UString& str) { return replace(0U, size(), U_STRING_TO_PARAM(str)); }
UString& replace(const char* s, uint32_t n) { return replace(0U, size(), s, n); }
UString& replace(uint32_t pos, uint32_t n, const char* s) { return replace(pos, n, s, u__strlen(s, __PRETTY_FUNCTION__)); }
UString& replace(uint32_t pos, uint32_t n, const UString& str) { return replace(pos, n, U_STRING_TO_PARAM(str)); }
// Assignment - NB: assign() DOES NOT WARRANT PROPERTIES OF STRING, replace() YES...
UString& assign(const char* s, uint32_t n);
UString& assign(const UString& str, uint32_t pos, uint32_t n = U_NOT_FOUND)
{
U_TRACE(0, "UString::assign(%p,%u,%u)", &str, pos, n)
U_INTERNAL_ASSERT(pos <= str.size())
return assign(str.data() + pos, str.rep->fold(pos, n));
}
UString& assign(const char* s) { return assign(s, u__strlen(s, __PRETTY_FUNCTION__)); }
UString& assign(const UString& str) { return assign(U_STRING_TO_PARAM(str)); }
UString& assign(uint32_t n, unsigned char c) { return replace(0U, size(), n, c); }
UString& operator=(const char* s) { return assign(s); }
UString& operator=(unsigned char c) { return assign(1U, c); }
void shift(ptrdiff_t diff) { rep->shift(diff); }
// Make room for a total of n element
bool reserve(uint32_t n)
{
U_TRACE(0, "UString::reserve(%u)", n)
if (rep->space() < n)
{
_reserve(*this, rep->_length + n);
U_RETURN(true); // return true if it has changed rep...
}
U_RETURN(false);
}
static void _reserve(UString& buffer, uint32_t n)
{
U_TRACE(0, "UString::_reserve(%V,%u)", buffer.rep, n)
UStringRep* rep = buffer.rep;
U_INTERNAL_DUMP("rep = %p rep->parent = %p rep->references = %u rep->child = %d rep->_length = %u rep->_capacity = %u",
rep, rep->parent, rep->references, rep->child, rep->_length, rep->_capacity)
U_ASSERT(rep->space() < n)
U_INTERNAL_ASSERT(n <= max_size())
U_INTERNAL_ASSERT_MAJOR(n, rep->_length)
buffer._set(UStringRep::create(rep->_length, n, rep->str));
U_INTERNAL_ASSERT(buffer.invariant())
}
// Element access
char at(uint32_t pos) const { return rep->at(pos); }
char operator[](uint32_t pos) const { return rep->operator[](pos); }
char* pend() const { return rep->pend(); }
// operator const char *() const { return rep->data(); }
// operator char *() { return rep->data(); }
// Modifiers
void push(unsigned char c) { (void) append(1U, c); }
void push_back(unsigned char c) { (void) append(1U, c); }
UString& append(uint32_t n, char c); // NB: unsigned char conflict with a uint32_t at the same parameter position...
UString& append(const char* s, uint32_t n)
{
U_TRACE(0, "UString::append(%.*S,%u)", n, s, n)
if (n)
{
char* ptr = __append(n);
U_MEMCPY(ptr, s, n);
}
U_INTERNAL_ASSERT(invariant())
return *this;
}
UString& append(const UString& str, uint32_t pos, uint32_t n = U_NOT_FOUND)
{
U_TRACE(0, "UString::append(%p,%u,%u)", &str, pos, n)
U_INTERNAL_ASSERT(pos <= str.size())
return append(str.data() + pos, str.rep->fold(pos, n));
}
UString& append(const char* s) { return append(s, u__strlen(s, __PRETTY_FUNCTION__)); }
UString& append(UStringRep* _rep) { return append(_rep->str, _rep->_length); }
UString& append(const UString& str) { return append(str.data(), str.size()); }
UString& operator+=(const char* s) { return append(s, u__strlen(s, __PRETTY_FUNCTION__)); }
UString& operator+=(unsigned char c) { return append(1U, c); }
UString& operator+=(const UString& str) { return append(str.data(), str.size()); }
// OPTMIZE APPEND (BUFFERED)
static char* ptrbuf;
static char* appbuf;
void _append(unsigned char c)
{
U_TRACE(0, "UString::_append(%C)", c)
U_INTERNAL_ASSERT_POINTER(ptrbuf)
U_INTERNAL_ASSERT_POINTER(appbuf)
if ((ptrbuf - appbuf) == 1024)
{
(void) append(appbuf, 1024);
ptrbuf = appbuf;
}
*ptrbuf++ = c;
}
void _append()
{
U_TRACE_NO_PARAM(0, "UString::_append()")
U_INTERNAL_ASSERT_POINTER(ptrbuf)
U_INTERNAL_ASSERT_POINTER(appbuf)
if (ptrbuf > appbuf)
{
(void) append(appbuf, ptrbuf - appbuf);
ptrbuf = appbuf;
}
}
// operator +
friend UString operator+(const UString& lhs, const char* rhs);
friend UString operator+(const UString& lhs, char rhs);
friend UString operator+(const UString& lhs, const UString& rhs);
friend UString operator+(char lhs, const UString& rhs);
friend UString operator+(const char* lhs, const UString& rhs);
UString& insert(uint32_t pos, const UString& str) { return replace(pos, 0, U_STRING_TO_PARAM(str)); }
UString& insert(uint32_t pos1, const UString& str, uint32_t pos2, uint32_t n = U_NOT_FOUND)
{
U_TRACE(0, "UString::insert(%u,%p,%u,%u)", pos1, &str, pos2, n)
U_INTERNAL_ASSERT(pos2 <= str.size())
return replace(pos1, 0, str.data() + pos2, str.rep->fold(pos2, n));
}
UString& insert(uint32_t pos, char c) { return replace(pos, 0, 1, c); }
UString& insert(uint32_t pos, uint32_t n, char c) { return replace(pos, 0, n, c); } // NB: uchar conflict with a uint32_t at the same parameter position
UString& insert(uint32_t pos, const char* s) { return replace(pos, 0, s, u__strlen(s, __PRETTY_FUNCTION__)); }
UString& insert(uint32_t pos, const char* s, uint32_t n) { return replace(pos, 0, s, n); }
void clear()
{
U_TRACE_NO_PARAM(0, "UString::clear()")
if (rep != UStringRep::string_rep_null) _assign(UStringRep::string_rep_null);
U_INTERNAL_ASSERT(invariant())
}
void resize(uint32_t n, unsigned char c);
// it can shrink the space used (capacity)...
bool shrink();
UString& erase(uint32_t pos = 0, uint32_t n = U_NOT_FOUND) { return replace(pos, rep->fold(pos, n), "", 0); }
// C-Style String
void setNullTerminated() const
{
U_TRACE_NO_PARAM(0, "UString::setNullTerminated()")
U_INTERNAL_ASSERT_MAJOR(rep->_length, 0)
if (writeable()) rep->setNullTerminated();
else ((UString*)this)->duplicate();
U_ASSERT_EQUALS(u__strlen(rep->str, __PRETTY_FUNCTION__), rep->_length)
}
char* c_str() const
{
U_TRACE_NO_PARAM(0, "UString::c_str()")
if (isNull() == false &&
isNullTerminated() == false)
{
setNullTerminated();
}
return (char*)rep->str;
}
char* c_strdup() const { return strndup(rep->str, rep->_length); }
char* c_strndup(uint32_t pos = 0, uint32_t n = U_NOT_FOUND) const { return strndup(rep->str+pos, rep->fold(pos, n)); }
UString copy() const
{
U_TRACE_NO_PARAM(0, "UString::copy()")
if (rep->_length)
{
U_INTERNAL_ASSERT_EQUALS(rep->_capacity, 0) // mode: 0 -> const
UString copia((void*)rep->str, rep->_length);
U_RETURN_STRING(copia);
}
return getStringNull();
}
uint32_t copy(char* s, uint32_t n = U_NOT_FOUND, uint32_t pos = 0) const { return rep->copy(s, n, pos); }
// STRING OPERATIONS
// The `find' function searches string for a specified string (possibly a single character) and returns
// its starting position. You can supply the parameter pos to specify the position where search must begin
uint32_t find(unsigned char c, uint32_t pos = 0, uint32_t how_much = U_NOT_FOUND) const __pure;
uint32_t find(const char* s, uint32_t pos, uint32_t s_len, uint32_t how_much = U_NOT_FOUND) const __pure;
uint32_t find(const UString& str, uint32_t pos = 0, uint32_t how_much = U_NOT_FOUND) const { return find(str.data(), pos, str.size(), how_much); }
// The `rfind' function searches from end to beginning string for a specified string (possibly a single character)
// and returns its starting position. You can supply the parameter pos to specify the position where search must begin
uint32_t rfind(const char* s, uint32_t pos, uint32_t n) const __pure;
uint32_t rfind(unsigned char c, uint32_t pos = U_NOT_FOUND) const __pure;
uint32_t rfind(const UString& str, uint32_t pos = U_NOT_FOUND) const { return rfind(str.data(), pos, str.size()); }
// The `find_first_of' function searches string for the first match of any character stored in s and returns its position
uint32_t find_first_of(const char* s, uint32_t pos, uint32_t n) const __pure;
uint32_t find_first_of(unsigned char c, uint32_t pos = 0) const { return find(c, pos); }
uint32_t find_first_of(const UString& str, uint32_t pos = 0) const { return find_first_of(str.data(), pos, str.size()); }
// The `find_last_of' function searches string for the last match of any character stored in s and returns its position
uint32_t find_last_of(const char* s, uint32_t pos, uint32_t n) const __pure;
uint32_t find_last_of(unsigned char c, uint32_t pos = U_NOT_FOUND) const { return rfind(c, pos); }
uint32_t find_last_of(const UString& str, uint32_t pos = U_NOT_FOUND) const { return find_last_of(str.data(), pos, str.size()); }
// The `find_first_not_of' function searches the first element of string that doesn't match any character stored in s and returns its position
uint32_t find_first_not_of(const char* s, uint32_t pos, uint32_t n) const __pure;
uint32_t find_first_not_of(unsigned char c, uint32_t pos = 0) const __pure;
uint32_t find_first_not_of(const UString& str, uint32_t pos = 0) const { return find_first_not_of(str.data(), pos, str.size()); }
// The `find_last_not_of' function searches the last element of string that doesn't match any character stored in s and returns its position
uint32_t find_last_not_of(const char* s, uint32_t pos, uint32_t n) const __pure;
uint32_t find_last_not_of(unsigned char c, uint32_t pos = U_NOT_FOUND) const __pure;
uint32_t find_last_not_of(const UString& str, uint32_t pos = U_NOT_FOUND) const { return find_last_not_of(str.data(), pos, str.size()); }
// Find with ignore case
uint32_t findnocase(const char* s, uint32_t pos, uint32_t s_len, uint32_t how_much = U_NOT_FOUND) const __pure;
uint32_t findnocase(const UString& str, uint32_t pos = 0, uint32_t how_much = U_NOT_FOUND) const { return findnocase(str.data(), pos, str.size(), how_much); }
uint32_t findWhiteSpace(uint32_t pos = 0) const __pure { return rep->findWhiteSpace(pos); }
// Compare
int compare(const char* s) const { return rep->compare(s, u__strlen(s, __PRETTY_FUNCTION__)); }
int compare(const char* s, uint32_t n) const { return rep->compare(s, n); }
int compare(UStringRep* _rep) const { return rep->compare(_rep); }
int compare(const UString& str) const { return rep->compare(str.rep); }
int compare(uint32_t pos, const char* s) const
{ return rep->compare(pos, u__strlen(s, __PRETTY_FUNCTION__), s, u__strlen(s, __PRETTY_FUNCTION__)); }
int compare(uint32_t pos, uint32_t n1, const char* s, uint32_t n2) const
{ return rep->compare(pos, U_min(size() - pos, n1), s, U_min(u__strlen(s, __PRETTY_FUNCTION__), n2)); }
int compare(uint32_t pos, uint32_t n, const char* s) const
{ return rep->compare(pos, U_min(size() - pos, n), s, u__strlen(s, __PRETTY_FUNCTION__)); }
int compare(uint32_t pos, uint32_t n, const UString& str) const
{ return rep->compare(pos, U_min(size() - pos, n), U_STRING_TO_PARAM(str)); }
int compare(uint32_t pos1, uint32_t n1, const UString& str, uint32_t pos2, uint32_t n2) const
{ return rep->compare(pos1, U_min(size() - pos1, n1), str.data() + pos2, U_min(str.size() - pos2, n2)); }
// Compare with ignore case
int comparenocase(const char* s, uint32_t n) const { return rep->comparenocase(s, n); }
int comparenocase(const char* s) const { return rep->comparenocase(s, u__strlen(s, __PRETTY_FUNCTION__)); }
int comparenocase(UStringRep* _rep) const { return rep->comparenocase(_rep); }
int comparenocase(const UString& str) const { return rep->comparenocase(str.rep); }
// Same string representation
bool same(UStringRep* _rep) const { return (rep == _rep); }
bool same(const UString& str) const { return same(str.rep); }
// Equal
bool equal(char c) const { return rep->equal(c); }
bool equal(const char* s) const { return rep->equal(s, u__strlen(s, __PRETTY_FUNCTION__)); }
bool equal(const char* s, uint32_t n) const { return rep->equal(s, n); }
bool equal(UStringRep* _rep) const { return same(_rep) || rep->equal(_rep); }
bool equal(const UString& str) const { return equal(str.rep); }
// Equal with ignore case
bool equalnocase(char c) const { return rep->equalnocase(c); }
bool equalnocase(const char* s) const { return rep->equalnocase(s, u__strlen(s, __PRETTY_FUNCTION__)); }
bool equalnocase(const char* s, uint32_t n) const { return rep->equalnocase(s, n); }
bool equalnocase(UStringRep* _rep) const { return same(_rep) || rep->equalnocase(_rep); }
bool equalnocase(const UString& str) const { return equalnocase(str.rep); }
// STREAM
#ifdef U_STDCPP_ENABLE
istream& getline(istream& is, unsigned char delim = '\n');
friend U_EXPORT istream& operator>>(istream& is, UString& str);
friend U_EXPORT ostream& operator<<(ostream& os, const UString& str);
// --------------------------------------------------------------
// STREAM - EXTENSION TO STDLIBC++
// --------------------------------------------------------------
void get(istream& is);
void write(ostream& os) const { rep->write(os); }
// --------------------------------------------------------------
#endif
#ifdef DEBUG
bool invariant() const;
# ifdef U_STDCPP_ENABLE
const char* dump(bool reset) const;
# endif
#endif
// -----------------------------------------------------------------------------------------------------------------------
// START EXTENSION TO STDLIBC++
// -----------------------------------------------------------------------------------------------------------------------
bool isNull() const { return (rep == UStringRep::string_rep_null); }
bool isNullTerminated() const { return rep->isNullTerminated(); }
bool isXMacAddr() const { return rep->isXMacAddr(); }
bool isText(uint32_t pos = 0) const { return rep->isText(pos); }
bool isUTF8(uint32_t pos = 0) const { return rep->isUTF8(pos); }
bool isUTF16(uint32_t pos = 0) const { return rep->isUTF16(pos); }
bool isBinary(uint32_t pos = 0) const { return rep->isBinary(pos); }
bool isBase64(uint32_t pos = 0) const { return rep->isBase64(pos); }
bool isBase64Url(uint32_t pos = 0) const { return rep->isBase64Url(pos); }
bool isWhiteSpace(uint32_t pos = 0) const { return rep->isWhiteSpace(pos); }
bool isPrintable(uint32_t pos = 0, bool bline = false) const { return rep->isPrintable(pos, bline); }
bool isEndHeader(uint32_t pos = 0) const { return rep->isEndHeader(pos); }
bool findEndHeader(uint32_t pos = 0) const { return rep->findEndHeader(pos); }
char last_char() const { return rep->last_char(); }
char first_char() const { return rep->first_char(); }
void setLastChar(char c) { rep->setLastChar(c); }
char c_char(uint32_t pos) const { return rep->at(pos); }
char* c_pointer(uint32_t pos) const { return (char*)rep->c_pointer(pos); }
ptrdiff_t remain(const char* ptr) const { return rep->remain(ptr); }
uint32_t distance(const char* ptr) const { return rep->distance(ptr); }
void setFromInode(uint64_t* p) { (void) replace((const char*)p, sizeof(uint64_t)); }
uint32_t hash() const { return rep->hash(); }
uint32_t hashIgnoreCase() const { return rep->hashIgnoreCase(); }
// references
void hold() const { rep->hold(); }
void release() const { rep->release(); }
uint32_t reference() const { return rep->references; }
// for constant string
void trim() const { rep->trim(); }
// check if the string is quoted...
bool isQuoted(unsigned char c = '"') const { return rep->isQuoted(c); }
// ...unquote it
void unQuote();
bool needQuote() const { return rep->needQuote(); }
UString getUnQuoted()
{
U_TRACE_NO_PARAM(0, "UString::getUnQuoted()")
const char* ptr = rep->str;
if (ptr[0] == '"')
{
uint32_t sz = rep->_length;
U_INTERNAL_ASSERT_EQUALS(ptr[sz-1], '"')
UString copia(ptr+1, sz-2);
U_RETURN_STRING(copia);
}
return *this;
}
uint32_t getSpaceToDump() const { return rep->getSpaceToDump(); }
// set uniq
void duplicate()
{
U_TRACE_NO_PARAM(0, "UString::duplicate()")
uint32_t sz = size();
U_INTERNAL_ASSERT_MAJOR(sz, 0)
U_INTERNAL_ASSERT_EQUALS(rep->_capacity, 0) // mode: 0 -> const
_set(UStringRep::create(sz, sz, rep->str));
U_INTERNAL_ASSERT(invariant())
}
bool uniq() const { return rep->uniq(); }
bool writeable() const { return rep->writeable(); }
// manage UString as constant string...
void setConstant(const char* t, uint32_t tlen)
{
U_TRACE(0, "UString::setConstant(%.*S,%u)", tlen, t, tlen)
U_INTERNAL_ASSERT_MAJOR(tlen, 0)
UStringRep* r;
U_NEW(UStringRep, r, UStringRep(t, tlen))
_set(r);
U_INTERNAL_ASSERT(invariant())
U_INTERNAL_ASSERT_EQUALS(data(), t)
}
// manage UString as memory mapped area...
bool isMmap() const
{
U_TRACE_NO_PARAM(0, "UString::isMmap()")
if (rep->_capacity == U_NOT_FOUND) U_RETURN(true);
U_RETURN(false);
}
void mmap(const char* map, uint32_t len);
// manage UString as buffer...
void setEmpty()
{
U_TRACE_NO_PARAM(0, "UString::setEmpty()")
U_INTERNAL_ASSERT_DIFFERS(rep->_capacity, 0) // mode: 0 -> const
rep->size_adjust(0U);
}
void setEmptyForce()
{
U_TRACE_NO_PARAM(0, "UString::setEmptyForce()")
U_INTERNAL_ASSERT_DIFFERS(rep->_capacity, 0) // mode: 0 -> const
rep->size_adjust_force(0U);
}
void setBuffer(uint32_t n)
{
U_TRACE(0, "UString::setBuffer(%u)", n)
if (rep->references ||
n > rep->_capacity)
{
resize(n);
}
else
{
rep->_length = 0;
}
}
void setBufferForce(uint32_t n)
{
U_TRACE(0, "UString::setBufferForce(%u)", n)
if (n > rep->_capacity)
{
resize(n);
}
else
{
rep->_length = 0;
}
}
void moveToBeginDataInBuffer(uint32_t n)
{
U_TRACE(1, "UString::moveToBeginDataInBuffer(%u)", n)
U_INTERNAL_ASSERT_MAJOR(rep->_length, n)
U_INTERNAL_ASSERT_RANGE(1, n, max_size())
U_INTERNAL_ASSERT_MAJOR(rep->_capacity, n)
# if defined(DEBUG) && !defined(U_SUBSTR_INC_REF)
U_INTERNAL_ASSERT(rep->references == 0)
# endif
rep->_length -= n;
(void) U_SYSCALL(memmove, "%p,%p,%u", (void*)rep->str, rep->str + n, rep->_length);
U_INTERNAL_ASSERT(invariant())
}
static vpFpcu printValueToBuffer;
void printKeyValue(const char* key, uint32_t keylen, const char* data, uint32_t datalen);
void snprintf(const char* format, uint32_t fmt_size, ...)
{
U_TRACE(0, "UString::snprintf(%.*S,%u)", fmt_size, format, fmt_size)
U_INTERNAL_ASSERT_POINTER(format)
va_list argp;
va_start(argp, fmt_size);
UString::vsnprintf(format, fmt_size, argp);
va_end(argp);
}
void snprintf_add(const char* format, uint32_t fmt_size, ...)
{
U_TRACE(0, "UString::snprintf_add(%.*S,%u)", fmt_size, format, fmt_size)
U_INTERNAL_ASSERT_POINTER(format)
va_list argp;
va_start(argp, fmt_size);
UString::vsnprintf_add(format, fmt_size, argp);
va_end(argp);
}
void size_adjust() { rep->size_adjust(); }
void size_adjust(uint32_t value) { rep->size_adjust(value); }
void size_adjust(const char* ptr) { rep->size_adjust(ptr); }
void size_adjust_force() { rep->size_adjust_force(); }
void size_adjust_force(uint32_t value) { rep->size_adjust_force(value); }
void size_adjust_force(const char* ptr) { rep->size_adjust_force(ptr); }
void setUpTime()
{
U_TRACE_NO_PARAM(0, "UString::setUpTime()")
# ifdef DEBUG
vsnprintf_check(U_CONSTANT_TO_PARAM("1234567890"));
U_ASSERT(uniq())
# endif
char* ptr = (char*)rep->str;
ptr[(rep->_length = u_set_uptime(ptr))] = '\0';
U_INTERNAL_ASSERT(invariant())
}
void setFromNumber32(uint32_t number)
{
U_TRACE(0, "UString::setFromNumber32(%u)", number)
# ifdef DEBUG
vsnprintf_check(U_CONSTANT_TO_PARAM("1234567890"));
U_ASSERT(uniq())
# endif
char* ptr = (char*)rep->str;
ptr[(rep->_length = u_num2str32(number, ptr) - ptr)] = '\0';
U_INTERNAL_ASSERT(invariant())
}
void setFromNumber32s(int32_t number)
{
U_TRACE(0, "UString::setFromNumber32s(%d)", number)
# ifdef DEBUG
vsnprintf_check(U_CONSTANT_TO_PARAM("1234567890"));
U_ASSERT(uniq())
# endif
char* ptr = (char*)rep->str;
ptr[(rep->_length = u_num2str32s(number, ptr) - ptr)] = '\0';
U_INTERNAL_ASSERT(invariant())
}
#ifdef DEBUG
void vsnprintf_check(const char* format, uint32_t fmt_size) const;
#endif
void setFromNumber64(uint64_t number)
{
U_TRACE(0, "UString::setFromNumber64(%llu)", number)
# ifdef DEBUG
vsnprintf_check(U_CONSTANT_TO_PARAM("18446744073709551615"));
U_ASSERT(uniq())
# endif
char* ptr = (char*)rep->str;
ptr[(rep->_length = u_num2str64(number, ptr) - ptr)] = '\0';
U_INTERNAL_ASSERT(invariant())
}
void setFromNumber64s(int64_t number)
{
U_TRACE(0, "UString::setFromNumber64s(%lld)", number)
# ifdef DEBUG
vsnprintf_check(U_CONSTANT_TO_PARAM("18446744073709551615"));
U_ASSERT(uniq())
# endif
char* ptr = (char*)rep->str;
ptr[(rep->_length = u_num2str64s(number, ptr) - ptr)] = '\0';
U_INTERNAL_ASSERT(invariant())
}
void appendNumber32(uint32_t number)
{
U_TRACE(0, "UString::appendNumber32(%u)", number)
U_ASSERT_MAJOR(space(), 12)
char* ptr = pend();
rep->_length += u_num2str32(number, ptr) - ptr;
U_INTERNAL_ASSERT(invariant())
}
void appendNumber32s(int32_t number)
{
U_TRACE(0, "UString::appendNumber32s(%d)", number)
U_ASSERT_MAJOR(space(), 12)
char* ptr = pend();
rep->_length += u_num2str32s(number, ptr) - ptr;
U_INTERNAL_ASSERT(invariant())
}
void appendNumber64(uint64_t number)
{
U_TRACE(0, "UString::appendNumber64(%llu)", number)
U_ASSERT_MAJOR(space(), 22)
char* ptr = pend();
rep->_length += u_num2str64(number, ptr) - ptr;
U_INTERNAL_ASSERT(invariant())
}
void appendNumber64s(int64_t number)
{
U_TRACE(0, "UString::appendNumber64s(%lld)", number)
U_ASSERT_MAJOR(space(), 22)
char* ptr = pend();
rep->_length += u_num2str64s(number, ptr) - ptr;
U_INTERNAL_ASSERT(invariant())
}
void appendNumberDouble(double number)
{
U_TRACE(0, "UString::appendNumberDouble(%g)", number)
U_ASSERT_MAJOR(space(), 22)
char* ptr = pend();
rep->_length += u_dtoa(number, ptr) - ptr;
U_INTERNAL_ASSERT(invariant())
}
void appendData(const char* t, uint32_t tlen)
{
U_TRACE(0, "UString::appendData(%.*S,%u)", tlen, t, tlen)
U_ASSERT_MAJOR(space(), tlen)
U_INTERNAL_ASSERT_MAJOR(tlen, 0)
char* ptr = pend();
U_MEMCPY(ptr, t, tlen);
rep->_length += tlen;
U_INTERNAL_ASSERT(invariant())
}
void appendDataQuoted(const char* t, uint32_t tlen)
{
U_TRACE(0, "UString::appendDataQuoted(%.*S,%u)", tlen, t, tlen)
U_ASSERT_MAJOR(space(), tlen+2)
U_INTERNAL_ASSERT_EQUALS(u_is_quoted(t, tlen), false)
char* ptr = pend();
*ptr++ = '"';
if (tlen) U_MEMCPY(ptr, t, tlen);
ptr[tlen] = '"';
rep->_length += tlen+2;
U_INTERNAL_ASSERT(invariant())
}
void vsnprintf(const char* format, uint32_t fmt_size, va_list argp)
{
U_TRACE(0, "UString::vsnprintf(%.*S,%u)", fmt_size, format, fmt_size)
# ifdef DEBUG
vsnprintf_check(format, fmt_size);
# endif
rep->_length = u__vsnprintf(rep->data(), rep->_capacity+1, format, fmt_size, argp); // NB: +1 because we want space for null-terminator...
U_INTERNAL_DUMP("ret = %u buffer_size = %u", rep->_length, rep->_capacity+1)
U_INTERNAL_ASSERT(invariant())
}
void vsnprintf_add(const char* format, uint32_t fmt_size, va_list argp)
{
U_TRACE(0, "UString::vsnprintf_add(%.*S,%u)", fmt_size, format, fmt_size)
# ifdef DEBUG
vsnprintf_check(format, fmt_size);
# endif
uint32_t ret = u__vsnprintf(c_pointer(rep->_length), rep->space()+1, format, fmt_size, argp); // NB: +1 because we want space for null-terminator...
U_INTERNAL_DUMP("ret = %u buffer_size = %u", ret, rep->space()+1)
rep->_length += ret;
U_INTERNAL_ASSERT(invariant())
}
#ifdef HAVE_STRTOF
float strtof() const { return rep->strtof(); }
#endif
#ifdef HAVE_STRTOLD
long double strtold() const { return rep->strtold(); }
#endif
bool strtob() const { return rep->strtob(); }
double strtod() const;
int64_t strtoll( bool check_for_suffix = false) const { return rep->strtoll( check_for_suffix); }
uint64_t strtoull(bool check_for_suffix = false) const { return rep->strtoull(check_for_suffix); }
long strtol( bool check_for_suffix = false) const { return rep->strtol( check_for_suffix); }
unsigned long strtoul(bool check_for_suffix = false) const { return rep->strtoul(check_for_suffix); }
// UTF8 <--> ISO Latin 1
static UString toUTF8(const unsigned char* t, uint32_t tlen)
{
U_TRACE(0, "UString::toUTF8(%.*S,%u)", tlen, t, tlen)
if (tlen == 0) return *string_null;
UStringRep* rep = UStringRep::toUTF8(t, tlen);
UString utf8(&rep);
U_RETURN_STRING(utf8);
}
static UString fromUTF8(const unsigned char* t, uint32_t tlen)
{
U_TRACE(0, "UString::fromUTF8(%.*S,%u)", tlen, t, tlen)
if (tlen == 0) return *string_null;
UStringRep* rep = UStringRep::fromUTF8(t, tlen);
UString isolat1(&rep);
U_RETURN_STRING(isolat1);
}
template <typename T> void toJSON(const char* name, uint32_t sz, UJsonTypeHandler<T> member)
{
U_TRACE(0, "UString::toJSON<T>(%.*S,%u,%p)", sz, name, sz, &member)
U_ASSERT_MAJOR(space(), sz+6)
U_INTERNAL_ASSERT_MAJOR(sz, 0)
U_INTERNAL_ASSERT(u_is_quoted(name, sz))
char* ptr = pend();
U_MEMCPY(ptr, name, sz);
ptr[sz] = ':';
rep->_length += sz+1;
member.toJSON(*this);
__push(',');
}
template <typename T> void toJSON(const UString& name, UJsonTypeHandler<T> member)
{
U_TRACE(0, "UString::toJSON<T>(%V,%p)", name.rep, &member)
uint32_t tlen = name.size();
const char* t = name.data();
U_ASSERT_MAJOR(space(), tlen+6)
U_INTERNAL_ASSERT_MAJOR(tlen, 0)
U_INTERNAL_ASSERT_EQUALS(u_is_quoted(t, tlen), false)
char* ptr = pend();
*ptr++ = '"';
U_MEMCPY(ptr, t, tlen);
ptr += tlen;
u_put_unalignedp16(ptr, U_MULTICHAR_CONSTANT16('"',':'));
rep->_length += tlen+3;
member.toJSON(*this);
__push(',');
}
// -----------------------------------------------------------------------------------------------------------------------
// END EXTENSION TO STDLIBC++
// -----------------------------------------------------------------------------------------------------------------------
private:
char* __append(uint32_t n);
char* __replace(uint32_t pos, uint32_t n1, uint32_t n2);
void resize(uint32_t n)
{
U_TRACE(0, "UString::resize(%u)", n)
U_INTERNAL_ASSERT_RANGE(1, n, max_size())
U_INTERNAL_DUMP("rep = %p rep->parent = %p rep->references = %u rep->child = %d rep->_capacity = %u",
rep, rep->parent, rep->references, rep->child, rep->_capacity)
_set(UStringRep::create(0U, (n < U_CAPACITY ? U_CAPACITY : n), U_NULLPTR));
U_INTERNAL_ASSERT(invariant())
}
void __push(uint8_t c)
{
U_TRACE(0, "UString::__push(%u)", c)
U_ASSERT_MAJOR(space(), 1)
uint8_t* ptr = (uint8_t*)(rep->str + rep->_length++);
*ptr = c;
U_INTERNAL_ASSERT(invariant())
}
friend class UHTTP;
friend class URDBClient_Base;
template <class T> friend class UJsonTypeHandler;
};
// operator ==
inline bool operator==(const UStringRep& lhs, const UStringRep& rhs) { return lhs.equal(&rhs); }
inline bool operator==(const UString& lhs, const UString& rhs) { return lhs.equal(rhs); }
inline bool operator==(const char* lhs, const UString& rhs) { return rhs.equal(lhs); }
inline bool operator==(const UString& lhs, const char* rhs) { return lhs.equal(rhs); }
// operator !=
inline bool operator!=(const UStringRep& lhs, const UStringRep& rhs) { return lhs.equal(&rhs) == false; }
inline bool operator!=(const UString& lhs, const UString& rhs) { return lhs.equal(rhs) == false; }
inline bool operator!=(const char* lhs, const UString& rhs) { return rhs.equal(lhs) == false; }
inline bool operator!=(const UString& lhs, const char* rhs) { return lhs.equal(rhs) == false; }
// operator <
inline bool operator<(const UStringRep& lhs, const UStringRep& rhs) { return lhs.compare(&rhs) < 0; }
inline bool operator<(const UString& lhs, const UString& rhs) { return lhs.compare(rhs) < 0; }
inline bool operator<(const char* lhs, const UString& rhs) { return rhs.compare(lhs) > 0; }
inline bool operator<(const UString& lhs, const char* rhs) { return lhs.compare(rhs) < 0; }
// operator >
inline bool operator>(const UStringRep& lhs, const UStringRep& rhs) { return lhs.compare(&rhs) > 0; }
inline bool operator>(const UString& lhs, const UString& rhs) { return lhs.compare(rhs) > 0; }
inline bool operator>(const char* lhs, const UString& rhs) { return rhs.compare(lhs) < 0; }
inline bool operator>(const UString& lhs, const char* rhs) { return lhs.compare(rhs) > 0; }
// operator <=
inline bool operator<=(const UStringRep& lhs, const UStringRep& rhs) { return lhs.compare(&rhs) <= 0; }
inline bool operator<=(const UString& lhs, const UString& rhs) { return lhs.compare(rhs) <= 0; }
inline bool operator<=(const char* lhs, const UString& rhs) { return rhs.compare(lhs) >= 0; }
inline bool operator<=(const UString& lhs, const char* rhs) { return lhs.compare(rhs) <= 0; }
// operator >=
inline bool operator>=(const UStringRep& lhs, const UStringRep& rhs) { return lhs.compare(&rhs) >= 0; }
inline bool operator>=(const UString& lhs, const UString& rhs) { return lhs.compare(rhs) >= 0; }
inline bool operator>=(const char* lhs, const UString& rhs) { return rhs.compare(lhs) <= 0; }
inline bool operator>=(const UString& lhs, const char* rhs) { return lhs.compare(rhs) >= 0; }
// by Victor Stewart
#if defined(U_STDCPP_ENABLE) && defined(HAVE_CXX11)
namespace std {
template<> struct hash<UString> {
std::size_t operator()(UString const& str) const noexcept { return std::hash<char *>()(str.c_str()); }
};
}
#endif
#endif