1
0
mirror of https://github.com/stefanocasazza/ULib.git synced 2025-09-28 19:05:55 +08:00
ULib/src/ulib/string.cpp
2017-12-05 17:33:34 +01:00

2614 lines
77 KiB
C++

// ============================================================================
//
// = LIBRARY
// ULib - c++ library
//
// = FILENAME
// string.cpp
//
// = AUTHOR
// Stefano Casazza
//
// ============================================================================
#include <ulib/file.h>
#include <ulib/json/value.h>
#include <ulib/utility/escape.h>
#include <ulib/internal/chttp.h>
vpFpcu UString::printValueToBuffer;
UString* UString::string_null = ULib::uustringnull.p2;
UStringRep* UStringRep::string_rep_null = ULib::uustringrepnull.p2;
UStringRep* UString::pkey;
// OPTMIZE APPEND (BUFFERED)
char* UString::appbuf;
char* UString::ptrbuf;
const UString* UString::str_host;
const UString* UString::str_chunked;
const UString* UString::str_without_mac;
const UString* UString::str_localhost;
const UString* UString::str_http;
const UString* UString::str_msg_rfc;
const UString* UString::str_txt_plain;
const UString* UString::str_address;
const UString* UString::str_CLIENT_QUEUE_DIR;
const UString* UString::str_point;
const UString* UString::str_true;
const UString* UString::str_false;
const UString* UString::str_response;
const UString* UString::str_zero;
const UString* UString::str_nostat;
const UString* UString::str_tsa;
const UString* UString::str_soap;
// SOAP
const UString* UString::str_ns;
const UString* UString::str_boolean;
const UString* UString::str_byte;
const UString* UString::str_unsignedByte;
const UString* UString::str_short;
const UString* UString::str_unsignedShort;
const UString* UString::str_int;
const UString* UString::str_unsignedInt;
const UString* UString::str_long;
const UString* UString::str_unsignedLong;
const UString* UString::str_float;
const UString* UString::str_double;
const UString* UString::str_string;
const UString* UString::str_base64Binary;
// IMAP
const UString* UString::str_recent;
const UString* UString::str_unseen;
const UString* UString::str_uidnext;
const UString* UString::str_uidvalidity;
// PROXY SERVICE
const UString* UString::str_FOLLOW_REDIRECTS;
const UString* UString::str_CLIENT_CERTIFICATE;
const UString* UString::str_REMOTE_ADDRESS_IP;
const UString* UString::str_WEBSOCKET;
// NOCAT
const UString* UString::str_without_label;
const UString* UString::str_allowed_members_default;
// SSI
const UString* UString::str_cgi;
const UString* UString::str_var;
// HTTP
const UString* UString::str_origin;
const UString* UString::str_ctype_tsa;
const UString* UString::str_ctype_txt;
const UString* UString::str_ctype_html;
const UString* UString::str_ctype_soap;
const UString* UString::str_ulib_header;
const UString* UString::str_storage_keyid;
const UString* UString::str_websocket_key;
const UString* UString::str_websocket_prot;
// QUERY PARSER
const UString* UString::str_p1;
const UString* UString::str_p2;
const UString* UString::str_or;
const UString* UString::str_and;
const UString* UString::str_not;
// ORM
const UString* UString::str_port;
const UString* UString::str_root;
const UString* UString::str_UTF8;
const UString* UString::str_UTF16;
const UString* UString::str_dbname;
const UString* UString::str_timeout;
const UString* UString::str_compress;
const UString* UString::str_character_set;
// ORM MYSQL
const UString* UString::str_mysql_name;
const UString* UString::str_secure_auth;
const UString* UString::str_auto_reconnect;
// ORM PGSQL
const UString* UString::str_pgsql_name;
// ORM SQLITE
const UString* UString::str_sqlite_name;
const UString* UString::str_dbdir;
const UString* UString::str_memory;
#ifndef U_HTTP2_DISABLE
const UString* UString::str_authority;
const UString* UString::str_method;
const UString* UString::str_method_get;
const UString* UString::str_method_post;
const UString* UString::str_path;
const UString* UString::str_path_root;
const UString* UString::str_path_index;
const UString* UString::str_scheme;
const UString* UString::str_scheme_https;
const UString* UString::str_status;
const UString* UString::str_status_200;
const UString* UString::str_status_204;
const UString* UString::str_status_206;
const UString* UString::str_status_304;
const UString* UString::str_status_400;
const UString* UString::str_status_404;
const UString* UString::str_status_500;
const UString* UString::str_accept_charset;
const UString* UString::str_accept_encoding;
const UString* UString::str_accept_encoding_value;
const UString* UString::str_accept_language;
const UString* UString::str_accept_ranges;
const UString* UString::str_accept;
const UString* UString::str_access_control_allow_origin;
const UString* UString::str_age;
const UString* UString::str_allow;
const UString* UString::str_authorization;
const UString* UString::str_cache_control;
const UString* UString::str_content_disposition;
const UString* UString::str_content_encoding;
const UString* UString::str_content_language;
const UString* UString::str_content_length;
const UString* UString::str_content_location;
const UString* UString::str_content_range;
const UString* UString::str_content_type;
const UString* UString::str_cookie;
const UString* UString::str_date;
const UString* UString::str_etag;
const UString* UString::str_expect;
const UString* UString::str_expires;
const UString* UString::str_from;
const UString* UString::str_if_match;
const UString* UString::str_if_modified_since;
const UString* UString::str_if_none_match;
const UString* UString::str_if_range;
const UString* UString::str_if_unmodified_since;
const UString* UString::str_last_modified;
const UString* UString::str_link;
const UString* UString::str_location;
const UString* UString::str_max_forwards;
const UString* UString::str_proxy_authenticate;
const UString* UString::str_proxy_authorization;
const UString* UString::str_range;
const UString* UString::str_referer;
const UString* UString::str_refresh;
const UString* UString::str_retry_after;
const UString* UString::str_server;
const UString* UString::str_set_cookie;
const UString* UString::str_strict_transport_security;
const UString* UString::str_transfer_encoding;
const UString* UString::str_user_agent;
const UString* UString::str_vary;
const UString* UString::str_via;
const UString* UString::str_www_authenticate;
const UString* UString::str_ULib;
#endif
#ifdef U_HTTP2_DISABLE
static ustringrep stringrep_storage[70] = {
#else
static ustringrep stringrep_storage[135] = {
#endif
{ U_STRINGREP_FROM_CONSTANT("host") },
{ U_STRINGREP_FROM_CONSTANT("chunked") },
{ U_STRINGREP_FROM_CONSTANT("00:00:00:00:00:00") },
{ U_STRINGREP_FROM_CONSTANT("localhost") },
{ U_STRINGREP_FROM_CONSTANT("http") },
{ U_STRINGREP_FROM_CONSTANT("message/rfc822") },
{ U_STRINGREP_FROM_CONSTANT("text/plain") },
{ U_STRINGREP_FROM_CONSTANT("stefano.casazza@gmail.com") },
{ U_STRINGREP_FROM_CONSTANT("/tmp/uclient") },
{ U_STRINGREP_FROM_CONSTANT(".") },
{ U_STRINGREP_FROM_CONSTANT("true") },
{ U_STRINGREP_FROM_CONSTANT("false") },
{ U_STRINGREP_FROM_CONSTANT("response") },
{ U_STRINGREP_FROM_CONSTANT("0") },
{ U_STRINGREP_FROM_CONSTANT("/nostat") },
{ U_STRINGREP_FROM_CONSTANT("/tsa") },
{ U_STRINGREP_FROM_CONSTANT("/soap") },
{ U_STRINGREP_FROM_CONSTANT("") },
// SOAP
{ U_STRINGREP_FROM_CONSTANT("ns") },
{ U_STRINGREP_FROM_CONSTANT("boolean") },
{ U_STRINGREP_FROM_CONSTANT("byte") },
{ U_STRINGREP_FROM_CONSTANT("unsignedByte") },
{ U_STRINGREP_FROM_CONSTANT("short") },
{ U_STRINGREP_FROM_CONSTANT("unsignedShort") },
{ U_STRINGREP_FROM_CONSTANT("int") },
{ U_STRINGREP_FROM_CONSTANT("unsignedInt") },
{ U_STRINGREP_FROM_CONSTANT("long") },
{ U_STRINGREP_FROM_CONSTANT("unsignedLong") },
{ U_STRINGREP_FROM_CONSTANT("float") },
{ U_STRINGREP_FROM_CONSTANT("double") },
{ U_STRINGREP_FROM_CONSTANT("string") },
{ U_STRINGREP_FROM_CONSTANT("base64Binary") },
// IMAP
{ U_STRINGREP_FROM_CONSTANT("RECENT") },
{ U_STRINGREP_FROM_CONSTANT("UNSEEN") },
{ U_STRINGREP_FROM_CONSTANT("UIDNEXT") },
{ U_STRINGREP_FROM_CONSTANT("UIDVALIDITY") },
// SSI
{ U_STRINGREP_FROM_CONSTANT("cgi") },
{ U_STRINGREP_FROM_CONSTANT("var") },
// NOCAT
{ U_STRINGREP_FROM_CONSTANT("without_label") },
{ U_STRINGREP_FROM_CONSTANT("/etc/nodog.allowed") },
// HTTP
{ U_STRINGREP_FROM_CONSTANT("application/timestamp-reply\r\n") },
{ U_STRINGREP_FROM_CONSTANT(U_CTYPE_TEXT_WITH_CHARSET U_CRLF) },
{ U_STRINGREP_FROM_CONSTANT(U_CTYPE_HTML U_CRLF) },
{ U_STRINGREP_FROM_CONSTANT("application/soap+xml; charset=\"utf-8\"\r\n") },
{ U_STRINGREP_FROM_CONSTANT("Origin") },
{ U_STRINGREP_FROM_CONSTANT("X-Powered-By: ULib/" ULIB_VERSION "\r\n") },
{ U_STRINGREP_FROM_CONSTANT("StiD") },
{ U_STRINGREP_FROM_CONSTANT("Sec-WebSocket-Key") },
{ U_STRINGREP_FROM_CONSTANT("Sec-WebSocket-Protocol") },
// QUERY PARSER
{ U_STRINGREP_FROM_CONSTANT("(") },
{ U_STRINGREP_FROM_CONSTANT(")") },
{ U_STRINGREP_FROM_CONSTANT("OR") },
{ U_STRINGREP_FROM_CONSTANT("AND") },
{ U_STRINGREP_FROM_CONSTANT("NOT") },
// ORM
{ U_STRINGREP_FROM_CONSTANT("port") },
{ U_STRINGREP_FROM_CONSTANT("root") },
{ U_STRINGREP_FROM_CONSTANT("utf8") },
{ U_STRINGREP_FROM_CONSTANT("utf16") },
{ U_STRINGREP_FROM_CONSTANT("dbname") },
{ U_STRINGREP_FROM_CONSTANT("timeout") },
{ U_STRINGREP_FROM_CONSTANT("compress") },
{ U_STRINGREP_FROM_CONSTANT("character-set") },
// ORM SQLITE
{ U_STRINGREP_FROM_CONSTANT("sqlite") },
{ U_STRINGREP_FROM_CONSTANT("dbdir") },
{ U_STRINGREP_FROM_CONSTANT(":memory:") },
// ORM MYSQL
{ U_STRINGREP_FROM_CONSTANT("mysql") },
{ U_STRINGREP_FROM_CONSTANT("secure-auth") },
{ U_STRINGREP_FROM_CONSTANT("auto-reconnect") },
// ORM PGSQL
{ U_STRINGREP_FROM_CONSTANT("pgsql") },
#ifndef U_HTTP2_DISABLE
{ U_STRINGREP_FROM_CONSTANT(":authority") },
{ U_STRINGREP_FROM_CONSTANT(":method") },
{ U_STRINGREP_FROM_CONSTANT("GET") },
{ U_STRINGREP_FROM_CONSTANT("POST") },
{ U_STRINGREP_FROM_CONSTANT(":path") },
{ U_STRINGREP_FROM_CONSTANT("/") },
{ U_STRINGREP_FROM_CONSTANT("/index.html") },
{ U_STRINGREP_FROM_CONSTANT(":scheme") },
{ U_STRINGREP_FROM_CONSTANT("https") },
{ U_STRINGREP_FROM_CONSTANT(":status") },
{ U_STRINGREP_FROM_CONSTANT("200") },
{ U_STRINGREP_FROM_CONSTANT("204") },
{ U_STRINGREP_FROM_CONSTANT("206") },
{ U_STRINGREP_FROM_CONSTANT("304") },
{ U_STRINGREP_FROM_CONSTANT("400") },
{ U_STRINGREP_FROM_CONSTANT("404") },
{ U_STRINGREP_FROM_CONSTANT("500") },
{ U_STRINGREP_FROM_CONSTANT("accept-charset") },
{ U_STRINGREP_FROM_CONSTANT("accept-encoding") },
{ U_STRINGREP_FROM_CONSTANT("gzip, deflate") },
{ U_STRINGREP_FROM_CONSTANT("accept-language") },
{ U_STRINGREP_FROM_CONSTANT("accept-ranges") },
{ U_STRINGREP_FROM_CONSTANT("accept") },
{ U_STRINGREP_FROM_CONSTANT("access-control-allow-origin") },
{ U_STRINGREP_FROM_CONSTANT("age") },
{ U_STRINGREP_FROM_CONSTANT("allow") },
{ U_STRINGREP_FROM_CONSTANT("authorization") },
{ U_STRINGREP_FROM_CONSTANT("cache-control") },
{ U_STRINGREP_FROM_CONSTANT("content-disposition") },
{ U_STRINGREP_FROM_CONSTANT("content-encoding") },
{ U_STRINGREP_FROM_CONSTANT("content-language") },
{ U_STRINGREP_FROM_CONSTANT("content-length") },
{ U_STRINGREP_FROM_CONSTANT("content-location") },
{ U_STRINGREP_FROM_CONSTANT("content-range") },
{ U_STRINGREP_FROM_CONSTANT("content-type") },
{ U_STRINGREP_FROM_CONSTANT("cookie") },
{ U_STRINGREP_FROM_CONSTANT("date") },
{ U_STRINGREP_FROM_CONSTANT("etag") },
{ U_STRINGREP_FROM_CONSTANT("expect") },
{ U_STRINGREP_FROM_CONSTANT("expires") },
{ U_STRINGREP_FROM_CONSTANT("from") },
{ U_STRINGREP_FROM_CONSTANT("if-match") },
{ U_STRINGREP_FROM_CONSTANT("if-modified-since") },
{ U_STRINGREP_FROM_CONSTANT("if-none-match") },
{ U_STRINGREP_FROM_CONSTANT("if-range") },
{ U_STRINGREP_FROM_CONSTANT("if-unmodified-since") },
{ U_STRINGREP_FROM_CONSTANT("last-modified") },
{ U_STRINGREP_FROM_CONSTANT("link") },
{ U_STRINGREP_FROM_CONSTANT("location") },
{ U_STRINGREP_FROM_CONSTANT("max-forwards") },
{ U_STRINGREP_FROM_CONSTANT("proxy-authenticate") },
{ U_STRINGREP_FROM_CONSTANT("proxy-authorization") },
{ U_STRINGREP_FROM_CONSTANT("range") },
{ U_STRINGREP_FROM_CONSTANT("referer") },
{ U_STRINGREP_FROM_CONSTANT("refresh") },
{ U_STRINGREP_FROM_CONSTANT("retry-after") },
{ U_STRINGREP_FROM_CONSTANT("server") },
{ U_STRINGREP_FROM_CONSTANT("set-cookie") },
{ U_STRINGREP_FROM_CONSTANT("strict-transport-security") },
{ U_STRINGREP_FROM_CONSTANT("transfer-encoding") },
{ U_STRINGREP_FROM_CONSTANT("user-agent") },
{ U_STRINGREP_FROM_CONSTANT("vary") },
{ U_STRINGREP_FROM_CONSTANT("via") },
{ U_STRINGREP_FROM_CONSTANT("www-authenticate") },
{ U_STRINGREP_FROM_CONSTANT("ULib") }
#endif
};
void UString::str_allocate(int which)
{
U_TRACE(0+256, "UString::str_allocate(%d)", which)
if (which == 0)
{
U_INTERNAL_ASSERT_EQUALS(str_host, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_chunked, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_without_mac, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_localhost, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_http, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_msg_rfc, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_txt_plain, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_address, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_CLIENT_QUEUE_DIR, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_point, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_true, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_false, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_response, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_zero, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_nostat, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_tsa, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_soap, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(pkey, U_NULLPTR)
U_NEW_ULIB_OBJECT(UString, str_host, UString(stringrep_storage+0));
U_NEW_ULIB_OBJECT(UString, str_chunked, UString(stringrep_storage+1));
U_NEW_ULIB_OBJECT(UString, str_without_mac, UString(stringrep_storage+2));
U_NEW_ULIB_OBJECT(UString, str_localhost, UString(stringrep_storage+3));
U_NEW_ULIB_OBJECT(UString, str_http, UString(stringrep_storage+4));
U_NEW_ULIB_OBJECT(UString, str_msg_rfc, UString(stringrep_storage+5));
U_NEW_ULIB_OBJECT(UString, str_txt_plain, UString(stringrep_storage+6));
U_NEW_ULIB_OBJECT(UString, str_address, UString(stringrep_storage+7));
U_NEW_ULIB_OBJECT(UString, str_CLIENT_QUEUE_DIR, UString(stringrep_storage+8));
U_NEW_ULIB_OBJECT(UString, str_point, UString(stringrep_storage+9));
U_NEW_ULIB_OBJECT(UString, str_true, UString(stringrep_storage+10));
U_NEW_ULIB_OBJECT(UString, str_false, UString(stringrep_storage+11));
U_NEW_ULIB_OBJECT(UString, str_response, UString(stringrep_storage+12));
U_NEW_ULIB_OBJECT(UString, str_zero, UString(stringrep_storage+13));
U_NEW_ULIB_OBJECT(UString, str_nostat, UString(stringrep_storage+14));
U_NEW_ULIB_OBJECT(UString, str_tsa, UString(stringrep_storage+15));
U_NEW_ULIB_OBJECT(UString, str_soap, UString(stringrep_storage+16));
uustringrep key1 = { stringrep_storage+17 };
pkey = key1.p2;
U_INTERNAL_ASSERT(pkey->invariant())
U_INTERNAL_ASSERT_EQUALS(*str_without_mac, "00:00:00:00:00:00")
U_INTERNAL_ASSERT_EQUALS(*str_CLIENT_QUEUE_DIR, "/tmp/uclient")
}
else if ((which & STR_ALLOCATE_SOAP) != 0)
{
U_INTERNAL_ASSERT_EQUALS(str_ns, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_boolean, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_byte, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_unsignedByte, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_short, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_unsignedShort, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_int, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_unsignedInt, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_long, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_unsignedLong, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_float, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_double, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_string, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_base64Binary, U_NULLPTR)
U_NEW_ULIB_OBJECT(UString, str_ns, UString(stringrep_storage+STR_ALLOCATE_INDEX_SOAP+0));
U_NEW_ULIB_OBJECT(UString, str_boolean, UString(stringrep_storage+STR_ALLOCATE_INDEX_SOAP+1));
U_NEW_ULIB_OBJECT(UString, str_byte, UString(stringrep_storage+STR_ALLOCATE_INDEX_SOAP+2));
U_NEW_ULIB_OBJECT(UString, str_unsignedByte, UString(stringrep_storage+STR_ALLOCATE_INDEX_SOAP+3));
U_NEW_ULIB_OBJECT(UString, str_short, UString(stringrep_storage+STR_ALLOCATE_INDEX_SOAP+4));
U_NEW_ULIB_OBJECT(UString, str_unsignedShort, UString(stringrep_storage+STR_ALLOCATE_INDEX_SOAP+5));
U_NEW_ULIB_OBJECT(UString, str_int, UString(stringrep_storage+STR_ALLOCATE_INDEX_SOAP+6));
U_NEW_ULIB_OBJECT(UString, str_unsignedInt, UString(stringrep_storage+STR_ALLOCATE_INDEX_SOAP+7));
U_NEW_ULIB_OBJECT(UString, str_long, UString(stringrep_storage+STR_ALLOCATE_INDEX_SOAP+8));
U_NEW_ULIB_OBJECT(UString, str_unsignedLong, UString(stringrep_storage+STR_ALLOCATE_INDEX_SOAP+9));
U_NEW_ULIB_OBJECT(UString, str_float, UString(stringrep_storage+STR_ALLOCATE_INDEX_SOAP+10));
U_NEW_ULIB_OBJECT(UString, str_double, UString(stringrep_storage+STR_ALLOCATE_INDEX_SOAP+11));
U_NEW_ULIB_OBJECT(UString, str_string, UString(stringrep_storage+STR_ALLOCATE_INDEX_SOAP+12));
U_NEW_ULIB_OBJECT(UString, str_base64Binary, UString(stringrep_storage+STR_ALLOCATE_INDEX_SOAP+13));
}
else if ((which & STR_ALLOCATE_IMAP) != 0)
{
U_INTERNAL_ASSERT_EQUALS(str_recent, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_unseen, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_uidnext, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_uidvalidity, U_NULLPTR)
U_NEW_ULIB_OBJECT(UString, str_recent, UString(stringrep_storage+STR_ALLOCATE_INDEX_IMAP+0));
U_NEW_ULIB_OBJECT(UString, str_unseen, UString(stringrep_storage+STR_ALLOCATE_INDEX_IMAP+1));
U_NEW_ULIB_OBJECT(UString, str_uidnext, UString(stringrep_storage+STR_ALLOCATE_INDEX_IMAP+2));
U_NEW_ULIB_OBJECT(UString, str_uidvalidity, UString(stringrep_storage+STR_ALLOCATE_INDEX_IMAP+3));
}
else if ((which & STR_ALLOCATE_SSI) != 0)
{
U_INTERNAL_ASSERT_EQUALS(str_cgi, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_var, U_NULLPTR)
U_NEW_ULIB_OBJECT(UString, str_cgi, UString(stringrep_storage+STR_ALLOCATE_INDEX_SSI+0));
U_NEW_ULIB_OBJECT(UString, str_var, UString(stringrep_storage+STR_ALLOCATE_INDEX_SSI+1));
}
else if ((which & STR_ALLOCATE_NOCAT) != 0)
{
U_INTERNAL_ASSERT_EQUALS(str_without_label, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_allowed_members_default, U_NULLPTR)
U_NEW_ULIB_OBJECT(UString, str_without_label, UString(stringrep_storage+STR_ALLOCATE_INDEX_NOCAT+0));
U_NEW_ULIB_OBJECT(UString, str_allowed_members_default, UString(stringrep_storage+STR_ALLOCATE_INDEX_NOCAT+1));
}
else if ((which & STR_ALLOCATE_HTTP) != 0)
{
U_INTERNAL_ASSERT_EQUALS(str_ctype_tsa, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_ctype_txt, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_ctype_html, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_ctype_soap, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_origin, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_ulib_header, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_storage_keyid, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_websocket_key, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_websocket_prot, U_NULLPTR)
U_NEW_ULIB_OBJECT(UString, str_ctype_tsa, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP+0));
U_NEW_ULIB_OBJECT(UString, str_ctype_txt, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP+1));
U_NEW_ULIB_OBJECT(UString, str_ctype_html, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP+2));
U_NEW_ULIB_OBJECT(UString, str_ctype_soap, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP+3));
U_NEW_ULIB_OBJECT(UString, str_origin, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP+4));
U_NEW_ULIB_OBJECT(UString, str_ulib_header, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP+5));
U_NEW_ULIB_OBJECT(UString, str_storage_keyid, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP+6));
U_NEW_ULIB_OBJECT(UString, str_websocket_key, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP+7));
U_NEW_ULIB_OBJECT(UString, str_websocket_prot, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP+8));
}
else if ((which & STR_ALLOCATE_QUERY_PARSER) != 0)
{
U_INTERNAL_ASSERT_EQUALS(str_p1, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_p2, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_or, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_and, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_not, U_NULLPTR)
U_NEW_ULIB_OBJECT(UString, str_p1, UString(stringrep_storage+STR_ALLOCATE_INDEX_QUERY_PARSER+0));
U_NEW_ULIB_OBJECT(UString, str_p2, UString(stringrep_storage+STR_ALLOCATE_INDEX_QUERY_PARSER+1));
U_NEW_ULIB_OBJECT(UString, str_or, UString(stringrep_storage+STR_ALLOCATE_INDEX_QUERY_PARSER+2));
U_NEW_ULIB_OBJECT(UString, str_and, UString(stringrep_storage+STR_ALLOCATE_INDEX_QUERY_PARSER+3));
U_NEW_ULIB_OBJECT(UString, str_not, UString(stringrep_storage+STR_ALLOCATE_INDEX_QUERY_PARSER+4));
}
else if ((which & STR_ALLOCATE_ORM) != 0)
{
U_INTERNAL_ASSERT_EQUALS(str_port, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_root, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_UTF8, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_UTF16, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_dbname, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_timeout, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_compress, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_character_set, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_sqlite_name, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_dbdir, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_memory, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_mysql_name, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_secure_auth, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_auto_reconnect, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(str_pgsql_name, U_NULLPTR)
U_NEW_ULIB_OBJECT(UString, str_port, UString(stringrep_storage+STR_ALLOCATE_INDEX_ORM+0));
U_NEW_ULIB_OBJECT(UString, str_root, UString(stringrep_storage+STR_ALLOCATE_INDEX_ORM+1));
U_NEW_ULIB_OBJECT(UString, str_UTF8, UString(stringrep_storage+STR_ALLOCATE_INDEX_ORM+2));
U_NEW_ULIB_OBJECT(UString, str_UTF16, UString(stringrep_storage+STR_ALLOCATE_INDEX_ORM+3));
U_NEW_ULIB_OBJECT(UString, str_dbname, UString(stringrep_storage+STR_ALLOCATE_INDEX_ORM+4));
U_NEW_ULIB_OBJECT(UString, str_timeout, UString(stringrep_storage+STR_ALLOCATE_INDEX_ORM+5));
U_NEW_ULIB_OBJECT(UString, str_compress, UString(stringrep_storage+STR_ALLOCATE_INDEX_ORM+6));
U_NEW_ULIB_OBJECT(UString, str_character_set, UString(stringrep_storage+STR_ALLOCATE_INDEX_ORM+7));
U_NEW_ULIB_OBJECT(UString, str_sqlite_name, UString(stringrep_storage+STR_ALLOCATE_INDEX_ORM+8));
U_NEW_ULIB_OBJECT(UString, str_dbdir, UString(stringrep_storage+STR_ALLOCATE_INDEX_ORM+9));
U_NEW_ULIB_OBJECT(UString, str_memory, UString(stringrep_storage+STR_ALLOCATE_INDEX_ORM+10));
U_NEW_ULIB_OBJECT(UString, str_mysql_name, UString(stringrep_storage+STR_ALLOCATE_INDEX_ORM+11));
U_NEW_ULIB_OBJECT(UString, str_secure_auth, UString(stringrep_storage+STR_ALLOCATE_INDEX_ORM+12));
U_NEW_ULIB_OBJECT(UString, str_auto_reconnect, UString(stringrep_storage+STR_ALLOCATE_INDEX_ORM+13));
U_NEW_ULIB_OBJECT(UString, str_pgsql_name, UString(stringrep_storage+STR_ALLOCATE_INDEX_ORM+14));
}
#ifndef U_HTTP2_DISABLE
else if ((which & STR_ALLOCATE_HTTP2) != 0)
{
U_INTERNAL_ASSERT_EQUALS(str_authority, U_NULLPTR)
U_INTERNAL_ASSERT_EQUALS(U_NUM_ELEMENTS(stringrep_storage), 135)
U_NEW_ULIB_OBJECT(UString, str_authority, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+0));
U_NEW_ULIB_OBJECT(UString, str_method, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+1));
U_NEW_ULIB_OBJECT(UString, str_method_get, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+2));
U_NEW_ULIB_OBJECT(UString, str_method_post, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+3));
U_NEW_ULIB_OBJECT(UString, str_path, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+4));
U_NEW_ULIB_OBJECT(UString, str_path_root, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+5));
U_NEW_ULIB_OBJECT(UString, str_path_index, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+6));
U_NEW_ULIB_OBJECT(UString, str_scheme, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+7));
U_NEW_ULIB_OBJECT(UString, str_scheme_https, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+8));
U_NEW_ULIB_OBJECT(UString, str_status, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+9));
U_NEW_ULIB_OBJECT(UString, str_status_200, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+10));
U_NEW_ULIB_OBJECT(UString, str_status_204, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+11));
U_NEW_ULIB_OBJECT(UString, str_status_206, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+12));
U_NEW_ULIB_OBJECT(UString, str_status_304, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+13));
U_NEW_ULIB_OBJECT(UString, str_status_400, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+14));
U_NEW_ULIB_OBJECT(UString, str_status_404, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+15));
U_NEW_ULIB_OBJECT(UString, str_status_500, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+16));
U_NEW_ULIB_OBJECT(UString, str_accept_charset, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+17));
U_NEW_ULIB_OBJECT(UString, str_accept_encoding, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+18));
U_NEW_ULIB_OBJECT(UString, str_accept_encoding_value, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+19));
U_NEW_ULIB_OBJECT(UString, str_accept_language, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+20));
U_NEW_ULIB_OBJECT(UString, str_accept_ranges, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+21));
U_NEW_ULIB_OBJECT(UString, str_accept, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+22));
U_NEW_ULIB_OBJECT(UString, str_access_control_allow_origin, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+23));
U_NEW_ULIB_OBJECT(UString, str_age, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+24));
U_NEW_ULIB_OBJECT(UString, str_allow, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+25));
U_NEW_ULIB_OBJECT(UString, str_authorization, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+26));
U_NEW_ULIB_OBJECT(UString, str_cache_control, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+27));
U_NEW_ULIB_OBJECT(UString, str_content_disposition, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+28));
U_NEW_ULIB_OBJECT(UString, str_content_encoding, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+29));
U_NEW_ULIB_OBJECT(UString, str_content_language, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+30));
U_NEW_ULIB_OBJECT(UString, str_content_length, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+31));
U_NEW_ULIB_OBJECT(UString, str_content_location, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+32));
U_NEW_ULIB_OBJECT(UString, str_content_range, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+33));
U_NEW_ULIB_OBJECT(UString, str_content_type, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+34));
U_NEW_ULIB_OBJECT(UString, str_cookie, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+35));
U_NEW_ULIB_OBJECT(UString, str_date, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+36));
U_NEW_ULIB_OBJECT(UString, str_etag, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+37));
U_NEW_ULIB_OBJECT(UString, str_expect, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+38));
U_NEW_ULIB_OBJECT(UString, str_expires, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+39));
U_NEW_ULIB_OBJECT(UString, str_from, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+40));
U_NEW_ULIB_OBJECT(UString, str_if_match, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+41));
U_NEW_ULIB_OBJECT(UString, str_if_modified_since, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+42));
U_NEW_ULIB_OBJECT(UString, str_if_none_match, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+43));
U_NEW_ULIB_OBJECT(UString, str_if_range, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+44));
U_NEW_ULIB_OBJECT(UString, str_if_unmodified_since, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+45));
U_NEW_ULIB_OBJECT(UString, str_last_modified, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+46));
U_NEW_ULIB_OBJECT(UString, str_link, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+47));
U_NEW_ULIB_OBJECT(UString, str_location, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+48));
U_NEW_ULIB_OBJECT(UString, str_max_forwards, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+49));
U_NEW_ULIB_OBJECT(UString, str_proxy_authenticate, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+50));
U_NEW_ULIB_OBJECT(UString, str_proxy_authorization, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+51));
U_NEW_ULIB_OBJECT(UString, str_range, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+52));
U_NEW_ULIB_OBJECT(UString, str_referer, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+53));
U_NEW_ULIB_OBJECT(UString, str_refresh, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+54));
U_NEW_ULIB_OBJECT(UString, str_retry_after, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+55));
U_NEW_ULIB_OBJECT(UString, str_server, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+56));
U_NEW_ULIB_OBJECT(UString, str_set_cookie, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+57));
U_NEW_ULIB_OBJECT(UString, str_strict_transport_security, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+58));
U_NEW_ULIB_OBJECT(UString, str_transfer_encoding, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+59));
U_NEW_ULIB_OBJECT(UString, str_user_agent, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+60));
U_NEW_ULIB_OBJECT(UString, str_vary, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+61));
U_NEW_ULIB_OBJECT(UString, str_via, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+62));
U_NEW_ULIB_OBJECT(UString, str_www_authenticate, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+63));
U_NEW_ULIB_OBJECT(UString, str_ULib, UString(stringrep_storage+STR_ALLOCATE_INDEX_HTTP2+64));
}
#else
U_INTERNAL_ASSERT_EQUALS(U_NUM_ELEMENTS(stringrep_storage), 70)
#endif
}
UStringRep* UStringRep::create(uint32_t length, uint32_t need, const char* ptr)
{
U_TRACE(1, "UStringRep::create(%u,%u,%p)", length, need, ptr)
U_INTERNAL_ASSERT_MAJOR(need, 0)
char* _ptr;
UStringRep* r;
// NB: we don't use new (ctor) because we want an allocation with more space for string data...
#ifndef ENABLE_MEMPOOL
r = (UStringRep*) U_SYSCALL(malloc, "%u", need+(1+sizeof(UStringRep)));
_ptr = (char*)(r + 1);
#else
if (need > U_CAPACITY)
{
_ptr = UFile::mmap(&need, -1, PROT_READ | PROT_WRITE, MAP_PRIVATE | U_MAP_ANON, 0);
if (_ptr == MAP_FAILED)
{
string_rep_null->references++;
U_RETURN_POINTER(string_rep_null, UStringRep);
}
r = U_MALLOC_TYPE(UStringRep);
}
else
{
# ifdef DEBUG
UMemoryPool::obj_class = "UStringRep";
UMemoryPool::func_call = __PRETTY_FUNCTION__;
# endif
// -------------------------------------------------------------------------------------------------------------------------------
// see: http://www.codeproject.com/Articles/702065/C-Struct-Hack
//
// NB: we need an array of char[_capacity], plus a terminating null char element, plus enough for the UStringRep data structure...
// -------------------------------------------------------------------------------------------------------------------------------
if (need > (U_STACK_TYPE_8-(1+sizeof(UStringRep))))
{
need = U_STACK_TYPE_9-(1+sizeof(UStringRep));
r = (UStringRep*) UMemoryPool::pop(9);
}
else
{
int stack_index;
uint32_t sz = need + (1+sizeof(UStringRep));
if (sz <= U_STACK_TYPE_4) // 128
{
need = U_STACK_TYPE_4-(1+sizeof(UStringRep));
stack_index = 4;
}
else if (sz <= U_STACK_TYPE_5) // 256
{
need = U_STACK_TYPE_5-(1+sizeof(UStringRep));
stack_index = 5;
}
else if (sz <= U_STACK_TYPE_6) // 512
{
need = U_STACK_TYPE_6-(1+sizeof(UStringRep));
stack_index = 6;
}
else if (sz <= U_STACK_TYPE_7) // 1024
{
need = U_STACK_TYPE_7-(1+sizeof(UStringRep));
stack_index = 7;
}
else
{
U_INTERNAL_ASSERT(need <= U_STACK_TYPE_8) // 2048
need = U_STACK_TYPE_8-(1+sizeof(UStringRep));
stack_index = 8;
}
U_INTERNAL_DUMP("sz = %u need = %u stack_index = %u", sz, need, stack_index)
r = (UStringRep*) UMemoryPool::pop(stack_index);
}
_ptr = (char*)(r + 1);
# ifdef DEBUG
UMemoryPool::obj_class = UMemoryPool::func_call = U_NULLPTR;
# endif
}
#endif
#ifdef DEBUG
U_SET_LOCATION_INFO;
U_REGISTER_OBJECT_PTR(0,UStringRep,r,&(r->memory._this))
r->memory._this = (void*)U_CHECK_MEMORY_SENTINEL;
#endif
r->set(length, need, _ptr);
if (length &&
ptr)
{
U_MEMCPY((void*)_ptr, ptr, length);
_ptr[length] = '\0';
}
U_INTERNAL_ASSERT(r->invariant())
U_RETURN_POINTER(r, UStringRep);
}
bool UString::shrink()
{
U_TRACE_NO_PARAM(0, "UString::shrink()")
#ifdef ENABLE_MEMPOOL
uint32_t _length = rep->_length, sz = _length+(1+sizeof(UStringRep)); // NB: we need an array of char[_length], plus a terminating null char, plus the UStringRep data structure...
U_INTERNAL_DUMP("rep->_capacity = %u _length = %u sz = %u", rep->_capacity, _length, sz)
U_INTERNAL_ASSERT_MAJOR(rep->_capacity, 0) // mode: 0 -> const
if (sz <= U_STACK_TYPE_8) // 2048
{
int stack_index;
uint32_t _capacity;
if (sz <= U_STACK_TYPE_4) // 128
{
_capacity = U_STACK_TYPE_4-(1+sizeof(UStringRep));
stack_index = 4;
}
else if (sz <= U_STACK_TYPE_5) // 256
{
_capacity = U_STACK_TYPE_5-(1+sizeof(UStringRep));
stack_index = 5;
}
else if (sz <= U_STACK_TYPE_6) // 512
{
_capacity = U_STACK_TYPE_6-(1+sizeof(UStringRep));
stack_index = 6;
}
else if (sz <= U_STACK_TYPE_7) // 1024
{
_capacity = U_STACK_TYPE_7-(1+sizeof(UStringRep));
stack_index = 7;
}
else // 2048
{
_capacity = U_STACK_TYPE_8-(1+sizeof(UStringRep));
stack_index = 8;
}
U_INTERNAL_DUMP("_capacity = %u stack_index = %u", _capacity, stack_index)
if (_capacity < rep->_capacity)
{
UStringRep* r = (UStringRep*) UMemoryPool::pop(stack_index);
char* ptr = (char*)(r + 1);
# ifdef DEBUG
U_SET_LOCATION_INFO;
U_REGISTER_OBJECT_PTR(0,UStringRep,r,&(r->memory._this))
r->memory._this = (void*)U_CHECK_MEMORY_SENTINEL;
# endif
r->set(_length, _capacity, ptr);
U_MEMCPY((void*)ptr, rep->str, _length);
ptr[_length] = '\0';
U_INTERNAL_ASSERT(r->invariant())
_set(r);
U_INTERNAL_ASSERT(invariant())
U_RETURN(true);
}
}
#endif
U_RETURN(false);
}
static const int MultiplyDeBruijnBitPosition2[32] = { 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 };
void UStringRep::_release()
{
U_TRACE_NO_PARAM(0, "UStringRep::_release()")
U_INTERNAL_DUMP("_capacity = %u str(%u) = %V", _capacity, _length, this)
U_INTERNAL_ASSERT_EQUALS(references, 0)
U_INTERNAL_ASSERT_DIFFERS(this, string_rep_null)
#if defined(U_SUBSTR_INC_REF) || defined(DEBUG)
if (parent)
# ifdef U_SUBSTR_INC_REF
parent->release(); // NB: only the death of substring de-reference the source...
# else
{
U_INTERNAL_ASSERT_EQUALS(child, 0)
U_INTERNAL_DUMP("parent->child = %d", parent->child)
// U_INTERNAL_ASSERT_RANGE(1, parent->child, max_child)
if (parent->child >= 1 &&
parent->child <= max_child)
{
parent->child--;
U_INTERNAL_DUMP("this = %p parent = %p parent->references = %u parent->child = %d", this, parent, parent->references, parent->child)
}
else
{
U_WARNING("parent->child has value(%d) out of range [1-%d]", parent->child, max_child);
}
}
else // source...
{
if (child)
{
# ifdef U_STDCPP_ENABLE
if (UObjectDB::fd > 0)
{
parent_destroy = this;
U_DUMP_OBJECT_WITH_CHECK("DEAD OF SOURCE STRING WITH CHILD ALIVE - child of this", checkIfChild)
}
else
# endif
{
char buffer[4096];
uint32_t len = u__snprintf(buffer, sizeof(buffer), U_CONSTANT_TO_PARAM("DEAD OF SOURCE STRING WITH CHILD ALIVE: child(%u) source(%u) = %V"), child, _length, this);
if (check_dead_of_source_string_with_child_alive)
{
U_INTERNAL_ASSERT_MSG(false, buffer)
}
else
{
U_WARNING("%.*s", len, buffer);
}
}
}
}
# endif
# ifdef DEBUG
U_UNREGISTER_OBJECT(0, this)
# endif
#endif
#ifndef ENABLE_MEMPOOL
U_SYSCALL_VOID(free, "%p", (void*)this);
#else
U_INTERNAL_DUMP("_capacity = %d (_capacity <= U_CAPACITY) = %b", (int32_t)_capacity, (_capacity <= U_CAPACITY))
if (_capacity <= U_CAPACITY)
{
if (_capacity == 0) UMemoryPool::push(this, U_SIZE_TO_STACK_INDEX(sizeof(UStringRep))); // NB: no room for data, which mean constant string...
else
{
// NB: we need an array of char[_capacity], plus a terminating null char element, plus enough for the UStringRep data structure...
uint32_t sz = _capacity + (1 + sizeof(UStringRep));
/**
* power of 2:
* -----------
* 2^7 128
* 2^8 256
* 2^9 512
* 2^10 1024
* 2^11 2048
* 2^12 4096
*/
U_INTERNAL_ASSERT_EQUALS(sz & (sz-1), 0) // must be a power of 2
UMemoryPool::push(this, MultiplyDeBruijnBitPosition2[(sz * 0x077CB531U) >> 27] - 3);
}
}
else
{
if (_capacity != U_NOT_FOUND)
{
# if defined(USE_LIBZOPFLI) || defined(USE_LIBTDB) || defined(USE_MONGODB)
if (_capacity == U_TO_FREE) { U_SYSCALL_VOID(free, "%p", (void*)str); }
else
# endif
UMemoryPool::deallocate((void*)str, _capacity);
}
else
{
ptrdiff_t resto = (ptrdiff_t)str % PAGESIZE;
U_INTERNAL_DUMP("resto = %u _length = %u", resto, _length)
if (resto)
{
str -= resto;
_length += resto;
}
// else _length += PAGESIZE;
(void) U_SYSCALL(munmap, "%p,%lu", (void*)str, _length);
}
U_FREE_TYPE(this, UStringRep); // NB: in debug mode the memory area is zeroed...
}
#endif
}
#ifdef DEBUG // substring capture event 'DEAD OF SOURCE STRING WITH CHILD ALIVE'...
int32_t UStringRep::max_child;
UStringRep* UStringRep::parent_destroy;
UStringRep* UStringRep::string_rep_share;
bool UStringRep::check_dead_of_source_string_with_child_alive = true;
bool UStringRep::checkIfReferences(const char* name_class, const void* ptr_object)
{
U_TRACE(0, "UStringRep::checkIfReferences(%S,%p)", name_class, ptr_object)
if (strncmp(name_class, U_CONSTANT_TO_PARAM("UString")) == 0)
{
U_INTERNAL_DUMP("references = %u", ((UString*)ptr_object)->rep->references)
if (((UString*)ptr_object)->rep == string_rep_share) U_RETURN(true);
}
U_RETURN(false);
}
bool UStringRep::checkIfChild(const char* name_class, const void* ptr_object)
{
U_TRACE(0, "UStringRep::checkIfChild(%S,%p)", name_class, ptr_object)
if (strncmp(name_class, U_CONSTANT_TO_PARAM("UStringRep")) == 0)
{
U_INTERNAL_DUMP("parent = %p", ((UStringRep*)ptr_object)->parent)
if (((UStringRep*)ptr_object)->parent == parent_destroy) U_RETURN(true);
}
U_RETURN(false);
}
#endif
UStringRep* UStringRep::substr(const char* t, uint32_t tlen) const
{
U_TRACE(0+256, "UStringRep::substr(%.*S,%u)", tlen, t, tlen)
U_CHECK_MEMORY
U_INTERNAL_ASSERT(tlen <= _length)
UStringRep* r;
if (tlen == 0)
{
r = string_rep_null;
r->references++;
}
else
{
U_INTERNAL_ASSERT_RANGE(str, t, pend())
U_NEW(UStringRep, r, UStringRep(t, tlen));
# if defined(U_SUBSTR_INC_REF) || defined(DEBUG)
UStringRep* p = (UStringRep*)this;
while (p->parent)
{
p = p->parent;
U_INTERNAL_ASSERT(p->invariant())
}
r->parent = p;
# ifdef U_SUBSTR_INC_REF
p->references++; // substring increment reference of source string
# else
p->child++; // substring capture event 'DEAD OF SOURCE STRING WITH CHILD ALIVE'...
max_child = U_max(max_child, p->child);
# endif
U_INTERNAL_DUMP("r->parent = %p max_child = %d", r->parent, max_child)
# endif
}
U_RETURN_POINTER(r, UStringRep);
}
__pure bool UStringRep::isSubStringOf(UStringRep* rep) const
{
U_TRACE(0, "UStringRep::isSubStringOf(%V)", rep)
U_CHECK_MEMORY
if (this != rep &&
_capacity == 0 && // mode: 0 -> const
data() >= rep->data() &&
pend() <= rep->pend())
{
# if defined(U_SUBSTR_INC_REF) || defined(DEBUG)
U_INTERNAL_ASSERT_EQUALS(parent, rep)
U_INTERNAL_ASSERT_MAJOR(rep->child, 0)
# endif
U_RETURN(true);
}
U_RETURN(false);
}
uint32_t UStringRep::copy(char* s, uint32_t n, uint32_t pos) const
{
U_TRACE(0, "UStringRep::copy(%p,%u,%u)", s, n, pos)
U_CHECK_MEMORY
U_INTERNAL_ASSERT(pos <= _length)
if (n > (_length - pos)) n = (_length - pos);
U_INTERNAL_ASSERT_MAJOR(n, 0)
U_MEMCPY(s, str + pos, n);
s[n] = '\0';
U_RETURN(n);
}
void UStringRep::trim()
{
U_TRACE_NO_PARAM(0, "UStringRep::trim()")
U_CHECK_MEMORY
U_INTERNAL_ASSERT_EQUALS(_capacity, 0)
// skip white space from start
while (_length && u__isspace(*str))
{
++str;
--_length;
}
U_INTERNAL_DUMP("_length = %u", _length)
// skip white space from end
while (_length && u__isspace(str[_length-1])) --_length;
}
__pure int UStringRep::compare(const UStringRep* rep, uint32_t depth) const
{
U_TRACE(0, "UStringRep::compare(%p,%u)", rep, depth)
U_CHECK_MEMORY
int r;
uint32_t min = U_min(_length, rep->_length);
U_INTERNAL_DUMP("min = %u", min)
if (depth > min) goto next;
r = memcmp(str + depth, rep->str + depth, min - depth);
U_INTERNAL_DUMP("str[%u] = %.*S", depth, min - depth, str + depth)
if (r == 0)
next:
r = (_length - rep->_length);
U_RETURN(r);
}
__pure bool UStringRep::isEndHeader(uint32_t pos) const
{
U_TRACE(0, "UStringRep::isEndHeader(%u)", pos)
U_CHECK_MEMORY
U_INTERNAL_ASSERT_MINOR(pos, _length)
const char* ptr = str + pos;
uint32_t _remain = (_length - pos);
if (_remain >= 4 &&
u_get_unalignedp32(ptr) == U_MULTICHAR_CONSTANT32('\r','\n','\r','\n'))
{
// U_line_terminator_len = 2;
U_INTERNAL_ASSERT(u__islterm(*ptr))
U_RETURN(true);
}
if (_remain >= 2 &&
u_get_unalignedp16(ptr) == U_MULTICHAR_CONSTANT16('\n','\n'))
{
// U_line_terminator_len = 1;
U_INTERNAL_ASSERT(u__islterm(*ptr))
U_RETURN(true);
}
U_RETURN(false);
}
UString::UString(uint32_t len, uint32_t sz, char* ptr) // NB: for UStringExt::deflate()...
{
U_TRACE_REGISTER_OBJECT_WITHOUT_CHECK_MEMORY(0, UString, "%u,%u,%p", len, sz, ptr)
U_INTERNAL_ASSERT_MAJOR(sz, U_CAPACITY)
U_ASSERT(UFile::checkPageAlignment(sz))
rep = U_MALLOC_TYPE(UStringRep);
#ifdef DEBUG
U_SET_LOCATION_INFO;
U_REGISTER_OBJECT_PTR(0,UStringRep,rep,&(rep->memory._this))
rep->memory._this = (void*)U_CHECK_MEMORY_SENTINEL;
#endif
rep->set(len, sz, ptr);
U_INTERNAL_ASSERT(invariant())
}
// SERVICES
UString& UString::assign(const char* s, uint32_t n)
{
U_TRACE(0, "UString::assign(%.*S,%u)", n, s, n)
if (rep->references ||
rep->_capacity < n)
{
if (n)
{
UStringRep* r;
U_NEW(UStringRep, r, UStringRep(s, n));
_set(r);
}
else
{
_assign(UStringRep::string_rep_null);
}
}
else
{
char* ptr = (char*)rep->str;
U_INTERNAL_ASSERT_MAJOR(n, 0)
U_INTERNAL_ASSERT_DIFFERS(ptr, s)
U_MEMCPY(ptr, s, n);
U_ASSERT(rep->uniq())
ptr[(rep->_length = n)] = '\0';
}
U_INTERNAL_ASSERT(invariant())
return *this;
}
void UString::setBuffer(uint32_t n)
{
U_TRACE(0, "UString::setBuffer(%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)
if (rep->references == 0 &&
n <= rep->_capacity)
{
((char*)rep->str)[(rep->_length = 0)] = '\0';
}
else
{
if (n < U_CAPACITY) n = U_CAPACITY;
_set(UStringRep::create(0U, n, U_NULLPTR));
}
U_INTERNAL_ASSERT(invariant())
}
// manage UString as memory mapped area...
void UString::mmap(const char* map, uint32_t len)
{
U_TRACE(0, "UString::mmap(%.*S,%u)", len, map, len)
U_INTERNAL_ASSERT_DIFFERS(map, MAP_FAILED)
if (isMmap())
{
U_ASSERT(uniq())
rep->str = map;
rep->_length = len;
}
else
{
UStringRep* r;
U_NEW(UStringRep, r, UStringRep(map, len));
_set(r);
rep->_capacity = U_NOT_FOUND;
}
U_INTERNAL_ASSERT(invariant())
// U_INTERNAL_ASSERT(isNullTerminated())
}
char* UString::__replace(uint32_t pos, uint32_t n1, uint32_t n2)
{
U_TRACE(0, "UString::__replace(%u,%u,%u)", pos, n1, n2)
U_INTERNAL_ASSERT_DIFFERS(n2, U_NOT_FOUND)
uint32_t sz = size();
U_INTERNAL_ASSERT(pos <= sz)
uint32_t sz1 = rep->fold(pos, n1),
n = sz + n2 - sz1;
U_INTERNAL_DUMP("sz1 = %u, n = %u", sz1, n)
if (n == 0)
{
_assign(UStringRep::string_rep_null);
return U_NULLPTR;
}
int32_t how_much = sz - pos - sz1;
U_INTERNAL_DUMP("how_much = %d", how_much)
U_INTERNAL_ASSERT(how_much >= 0)
char* str = (char*)rep->str;
const char* src = str + pos + sz1;
uint32_t __capacity = rep->_capacity;
if (__capacity == U_NOT_FOUND) __capacity = 0;
if (rep->references ||
n > __capacity)
{
U_INTERNAL_DUMP("__capacity = %u, n = %u", __capacity, n)
if (__capacity < n) __capacity = n;
UStringRep* r = UStringRep::create(n, __capacity, U_NULLPTR);
if (pos) U_MEMCPY((void*)r->str, str, pos);
if (how_much) U_MEMCPY((char*)r->str + pos + n2, src, how_much);
_set(r);
str = (char*)r->str;
}
else if (how_much > 0 &&
n1 != n2)
{
(void) U_SYSCALL(memmove, "%p,%p,%u", str + pos + n2, src, how_much);
}
U_ASSERT(uniq())
str[(rep->_length = n)] = '\0';
return str + pos;
}
void UString::unQuote()
{
U_TRACE_NO_PARAM(0, "UString::unQuote()")
uint32_t len = rep->_length;
if (len <= 2) _assign(UStringRep::string_rep_null);
else if (rep->_capacity == 0) rep->unQuote();
else
{
len -= 2;
char* ptr = (char*) rep->str;
if (rep->references)
{
UStringRep* r;
U_NEW(UStringRep, r, UStringRep(ptr+1, len));
_set(r);
}
else
{
(void) U_SYSCALL(memmove, "%p,%p,%u", ptr, ptr + 1, len);
ptr[(rep->_length = len)] = '\0';
}
}
}
char* UString::__append(uint32_t n)
{
U_TRACE(0, "UString::__append(%u)", n)
UStringRep* r;
char* str = (char*)rep->str;
uint32_t sz = rep->_length, need = sz + n;
U_INTERNAL_DUMP("need = %u", need)
U_INTERNAL_ASSERT_MAJOR(need, 0)
if (rep->references ||
need > rep->_capacity)
{
r = UStringRep::create(sz, (need < U_CAPACITY ? U_CAPACITY : (need * 2) + (PAGESIZE * 2)), str);
_set(r);
str = (char*)r->str;
}
U_ASSERT(uniq())
str[(rep->_length = need)] = '\0';
return str + sz;
}
UString& UString::append(uint32_t n, char c)
{
U_TRACE(1, "UString::append(%u,%C)", n, c)
if (n)
{
char* ptr = __append(n);
ptr[0] = c;
if (--n) (void) U_SYSCALL(memset, "%p,%d,%u", ptr+1, c, n);
}
U_INTERNAL_ASSERT(invariant())
return *this;
}
void UString::resize(uint32_t n, unsigned char c)
{
U_TRACE(0, "UString::resize(%u,%C)", n, c)
U_INTERNAL_ASSERT(n <= max_size())
uint32_t sz = size();
if (n > sz) (void) append(n - sz, c);
else if (n < sz) erase(n);
else size_adjust(n);
U_INTERNAL_ASSERT(invariant())
}
// 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
__pure uint32_t UString::find(const char* s, uint32_t pos, uint32_t s_len, uint32_t how_much) const
{
U_TRACE(0, "UString::find(%.*S,%u,%u,%u)", s_len, s, pos, s_len, how_much)
U_INTERNAL_ASSERT_MAJOR(s_len, 0)
// An empty string consists of no characters, therefore it should be found at every point in a UString, except beyond the end...
// if (s_len == 0) U_RETURN(pos <= size() ? pos : U_NOT_FOUND);
uint32_t n = rep->fold(pos, how_much);
U_INTERNAL_DUMP("rep->_length = %u", rep->_length)
U_INTERNAL_ASSERT(n <= rep->_length)
const char* str = rep->str;
const char* ptr = (const char*) u_find(str + pos, n, s, s_len);
n = (ptr ? ptr - str : U_NOT_FOUND);
U_RETURN(n);
}
__pure uint32_t UString::findnocase(const char* s, uint32_t pos, uint32_t s_len, uint32_t how_much) const
{
U_TRACE(0, "UString::findnocase(%.*S,%u,%u,%u)", s_len, s, pos, s_len, how_much)
U_INTERNAL_ASSERT_MAJOR(s_len, 1)
uint32_t n = rep->fold(pos, how_much);
int32_t __end = n - s_len + 1;
if (__end > 0)
{
const char* str = rep->str + pos;
for (int32_t xpos = 0; xpos < __end; ++xpos)
{
if (u__strncasecmp(str + xpos, s, s_len) == 0) U_RETURN(pos+xpos);
}
}
U_RETURN(U_NOT_FOUND);
}
// rfind() instead of starting at the beginning of the string and searching for the text's first occurence, starts its search at the end and returns the last occurence
__pure uint32_t UString::rfind(unsigned char c, uint32_t pos) const
{
U_TRACE(0, "UString::rfind(%C,%u)", c, pos)
uint32_t sz = size();
if (sz)
{
uint32_t xpos = sz - 1;
if (xpos > pos) xpos = pos;
for (++xpos; xpos-- > 0; )
{
if (rep->str[xpos] == c) U_RETURN(xpos);
}
}
U_RETURN(U_NOT_FOUND);
}
__pure uint32_t UString::rfind(const char* s, uint32_t pos, uint32_t n) const
{
U_TRACE(0, "UString::rfind(%.*S,%u,%u)", n, s, pos, n)
uint32_t sz = size();
if (n <= sz)
{
pos = U_min(sz - n, pos);
do {
if (memcmp(rep->str + pos, s, n) == 0) U_RETURN(pos);
}
while (pos-- > 0);
}
U_RETURN(U_NOT_FOUND);
}
// Instead of searching for the entire string, find_first_of() returns as soon as a single common element is found between the strings being compared.
// And yes, this means that the find_first_of() that take a single char are exactly the same as the find() functions with the same parameters...
__pure uint32_t UString::find_first_of(const char* s, uint32_t pos, uint32_t n) const
{
U_TRACE(0, "UString::find_first_of(%.*S,%u,%u)", n, s, pos, n)
if (n)
{
for (; pos < size(); ++pos)
{
if (memchr(s, rep->str[pos], n)) U_RETURN(pos);
}
}
U_RETURN(U_NOT_FOUND);
}
__pure uint32_t UString::find_last_of(const char* s, uint32_t pos, uint32_t n) const
{
U_TRACE(0, "UString::find_last_of(%.*S,%u,%u)", n, s, pos, n)
uint32_t sz = size();
if (sz && n)
{
if (--sz > pos) sz = pos;
do {
if (memchr(s, rep->str[sz], n)) U_RETURN(sz);
}
while (sz-- != 0);
}
U_RETURN(U_NOT_FOUND);
}
// Now these functions, instead of returning an index to the first common element, returns an index to the first non-common element...
__pure uint32_t UString::find_first_not_of(const char* s, uint32_t pos, uint32_t n) const
{
U_TRACE(0, "UString::find_first_not_of(%.*S,%u,%u)", n, s, pos, n)
if (n)
{
uint32_t sz = size(),
xpos = pos;
for (; xpos < sz; ++xpos)
{
if (memchr(s, rep->str[xpos], n) == U_NULLPTR) U_RETURN(xpos);
}
}
U_RETURN(U_NOT_FOUND);
}
__pure uint32_t UString::find_first_not_of(unsigned char c, uint32_t pos) const
{
U_TRACE(0, "UString::find_first_not_of(%C,%u)", c, pos)
uint32_t sz = size(),
xpos = pos;
const char* str = rep->str;
for (; xpos < sz; ++xpos)
{
if (str[xpos] != c) U_RETURN(xpos);
}
U_RETURN(U_NOT_FOUND);
}
__pure uint32_t UString::find_last_not_of(const char* s, uint32_t pos, uint32_t n) const
{
U_TRACE(0, "UString::find_last_not_of(%.*S,%u,%u)", n, s, pos, n)
uint32_t sz = size();
if (n &&
sz)
{
if (--sz > pos) sz = pos;
do {
if (memchr(s, rep->str[sz], n) == U_NULLPTR) U_RETURN(sz);
}
while (sz-- != 0);
}
U_RETURN(U_NOT_FOUND);
}
__pure uint32_t UString::find_last_not_of(unsigned char c, uint32_t pos) const
{
U_TRACE(0, "UString::find_last_not_of(%C,%u)", c, pos)
uint32_t sz = size();
if (sz)
{
uint32_t xpos = sz - 1;
if (xpos > pos) xpos = pos;
const char* str = rep->str;
for (++xpos; xpos-- > 0; )
{
if (str[xpos] != c) U_RETURN(xpos);
}
}
U_RETURN(U_NOT_FOUND);
}
// EXTENSION
__pure bool UStringRep::strtob() const
{
U_TRACE_NO_PARAM(0, "UStringRep::strtob()")
if (_length)
{
switch (u_get_unalignedp16(str))
{
case U_MULTICHAR_CONSTANT16('1',0):
case U_MULTICHAR_CONSTANT16('o','n'):
case U_MULTICHAR_CONSTANT16('O','n'):
case U_MULTICHAR_CONSTANT16('O','N'): U_RETURN(true);
}
switch (u_get_unalignedp32(str))
{
case U_MULTICHAR_CONSTANT32('y','e','s',0):
case U_MULTICHAR_CONSTANT32('Y','e','s',0):
case U_MULTICHAR_CONSTANT32('Y','E','S',0):
case U_MULTICHAR_CONSTANT32('t','r','u','e'):
case U_MULTICHAR_CONSTANT32('T','r','u','e'):
case U_MULTICHAR_CONSTANT32('T','R','U','E'): U_RETURN(true);
}
}
U_RETURN(false);
}
#define U_MANAGE_CHECK_FOR_SUFFIX \
if (check_for_suffix == false) while (u__isdigit(*(endptr-1)) == false) --endptr; \
else \
{ \
suffix = *(endptr-1); \
\
if (suffix != 'M' && \
suffix != 'G' && \
u__toupper(suffix) != 'K') \
{ \
suffix = 0; \
} \
else \
{ \
--endptr; \
\
U_INTERNAL_ASSERT(u__isdigit(*(endptr-1))) \
} \
}
__pure long UStringRep::strtol(bool check_for_suffix) const
{
U_TRACE(0, "UString::strtol(%b)", check_for_suffix)
if (_length)
{
char suffix = 0;
const char* s = str;
const char* endptr = str + _length;
while (u__isspace(*s)) ++s;
U_MANAGE_CHECK_FOR_SUFFIX
long value = u_strtol(s, endptr);
if (suffix)
{
U_NUMBER_SUFFIX(value, suffix);
}
U_RETURN(value);
}
U_RETURN(0);
}
__pure unsigned long UStringRep::strtoul(bool check_for_suffix) const
{
U_TRACE(0, "UString::strtoul(%b)", check_for_suffix)
if (_length)
{
char suffix = 0;
const char* s = str;
const char* endptr = str + _length;
while (u__isspace(*s)) ++s;
U_MANAGE_CHECK_FOR_SUFFIX
unsigned long value = u_strtoul(s, endptr);
if (suffix)
{
U_NUMBER_SUFFIX(value, suffix);
}
U_RETURN(value);
}
U_RETURN(0);
}
__pure int64_t UStringRep::strtoll(bool check_for_suffix) const
{
U_TRACE(0, "UString::strtoll(%b)", check_for_suffix)
if (_length)
{
char suffix = 0;
const char* s = str;
const char* endptr = str + _length;
while (u__isspace(*s)) ++s;
U_MANAGE_CHECK_FOR_SUFFIX
int64_t value = u_strtoll(s, endptr);
if (suffix)
{
U_NUMBER_SUFFIX(value, suffix);
}
U_RETURN(value);
}
U_RETURN(0);
}
__pure uint64_t UStringRep::strtoull(bool check_for_suffix) const
{
U_TRACE(0, "UString::strtoull(%b)", check_for_suffix)
if (_length)
{
char suffix = 0;
const char* s = str;
const char* endptr = str + _length;
while (u__isspace(*s)) ++s;
U_MANAGE_CHECK_FOR_SUFFIX
uint64_t value = u_strtoull(s, endptr);
if (suffix)
{
U_NUMBER_SUFFIX(value, suffix);
}
U_RETURN(value);
}
U_RETURN(0);
}
#undef U_MANAGE_CHECK_FOR_SUFFIX
#ifdef HAVE_STRTOF
// extern "C" { float strtof(const char* nptr, char** endptr); }
float UStringRep::strtof() const
{
U_TRACE_NO_PARAM(0, "UStringRep::strtof()")
if (_length)
{
char* eos = (char*)str + _length;
if (isNullTerminated() == false &&
writeable())
{
*eos = '\0';
}
# ifndef DEBUG
float result = ::strtof(str, 0);
# else
char* endptr;
float result = ::strtof(str, &endptr);
U_INTERNAL_ASSERT(endptr <= eos)
# endif
U_INTERNAL_DUMP("errno = %d", errno)
U_RETURN(result);
}
U_RETURN(0);
}
#endif
#ifdef HAVE_STRTOLD
// extern "C" { long double strtold(const char* nptr, char** endptr); }
long double UStringRep::strtold() const
{
U_TRACE_NO_PARAM(0, "UStringRep::strtold()")
if (_length)
{
char* eos = (char*)str + _length;
if (isNullTerminated() == false &&
writeable())
{
*eos = '\0';
}
# ifndef DEBUG
long double result = ::strtold(str, U_NULLPTR);
# else
char* endptr;
long double result = ::strtold(str, &endptr);
U_INTERNAL_ASSERT_MINOR(endptr, eos)
# endif
U_INTERNAL_DUMP("errno = %d", errno)
U_RETURN(result);
}
U_RETURN(0);
}
#endif
// UTF8 <--> ISO Latin 1
UStringRep* UStringRep::fromUTF8(const unsigned char* s, uint32_t n)
{
U_TRACE(0, "UStringRep::fromUTF8(%.*S,%u)", n, s, n)
U_INTERNAL_ASSERT_POINTER(s)
U_INTERNAL_ASSERT_MAJOR(n, 0)
int c, c1, c2;
UStringRep* r = UStringRep::create(n, n, U_NULLPTR);
char* p = (char*)r->str;
const unsigned char* _end = s + n;
while (s < _end)
{
if ( s < (_end - 1) &&
(*s & 0xE0) == 0xC0 &&
(*(s+1) & 0xC0) == 0x80)
{
c1 = *s++ & 0x1F;
c2 = *s++ & 0x3F;
c = (c1 << 6) + c2;
U_INTERNAL_DUMP("c = %d %C", c, (char)c)
}
else
{
c = *s++;
}
*p++ = (unsigned char)c;
}
r->_length = p - r->str;
U_INTERNAL_ASSERT(r->invariant())
U_RETURN_POINTER(r, UStringRep);
}
UStringRep* UStringRep::toUTF8(const unsigned char* s, uint32_t n)
{
U_TRACE(0, "UStringRep::toUTF8(%.*S,%u)", n, s, n)
U_INTERNAL_ASSERT_POINTER(s)
U_INTERNAL_ASSERT_MAJOR(n, 0)
UStringRep* r = UStringRep::create(n, n * 2, U_NULLPTR);
char* p = (char*)r->str;
const unsigned char* _end = s + n;
while (s < _end)
{
int c = *s++;
if (c >= 0x80)
{
*p++ = ((c >> 6) & 0x1F) | 0xC0;
*p++ = ( c & 0x3F) | 0x80;
continue;
}
*p++ = (unsigned char)c;
}
r->_length = p - r->str;
U_INTERNAL_ASSERT(r->invariant())
U_RETURN_POINTER(r, UStringRep);
}
double UString::strtod() const
{
U_TRACE_NO_PARAM(0, "UString::strtod()")
if (rep->equal(U_CONSTANT_TO_PARAM("0")) == false &&
rep->equal(U_CONSTANT_TO_PARAM("0.0")) == false)
{
UValue json;
if (json.parse(*this))
{
double result = (json.isDouble() ? json.getDouble() : (double)json.getPayload());
U_INTERNAL_DUMP("json.getDouble() = %g", json.getDouble())
U_RETURN(result);
}
}
U_RETURN(.0);
}
void UString::printKeyValue(const char* key, uint32_t keylen, const char* _data, uint32_t datalen)
{
U_TRACE(0, "UString::printKeyValue(%.*S,%u,%.*S,%u)", keylen, key, keylen, datalen, _data, datalen)
uint32_t n = 5 + 18 + keylen;
if (printValueToBuffer == U_NULLPTR) n += datalen;
else
{
U_INTERNAL_ASSERT_EQUALS(u_buffer_len, 0)
printValueToBuffer(_data, datalen);
U_INTERNAL_ASSERT_MINOR(u_buffer_len, U_BUFFER_SIZE)
n += u_buffer_len;
}
if (rep->space() < n) _reserve(*this, rep->_length + n);
char* ptr = (char*)rep->str + rep->_length;
ptr += u__snprintf(ptr, 40, U_CONSTANT_TO_PARAM("+%u,%u:"), keylen, datalen);
U_MEMCPY(ptr, key, keylen);
ptr += keylen;
U_MEMCPY(ptr, "->", U_CONSTANT_SIZE("->"));
ptr += U_CONSTANT_SIZE("->");
if (printValueToBuffer)
{
U_MEMCPY(ptr, u_buffer, u_buffer_len);
ptr += u_buffer_len;
u_buffer_len = 0;
}
else
{
U_MEMCPY(ptr, _data, datalen);
ptr += datalen;
}
u_put_unalignedp16(ptr, U_MULTICHAR_CONSTANT16('\n','\0'));
rep->_length = (ptr - rep->str) + 1;
U_INTERNAL_ASSERT(invariant())
}
void UString::setFromData(const char** p, uint32_t sz, unsigned char delim)
{
U_TRACE(0, "UString::setFromData(%.*S,%u,%C)", sz, *p, sz, delim)
U_INTERNAL_ASSERT_MAJOR(sz, 0)
U_INTERNAL_ASSERT_EQUALS(rep->_length, 0)
const char* ptr = *p;
unsigned char c = *ptr;
const char* _pend = ptr + sz;
U_INTERNAL_DUMP("c = %C", c)
if (u__isspace(c))
{
// skip white space
while (u__isspace(*++ptr)) {}
U_INTERNAL_ASSERT_MINOR(ptr, _pend)
c = *ptr;
}
if (c == '@' &&
UVector<void*>::istream_loading == false)
{
// get content pointed by string 'meta' (that start with '@')
if (u_get_unalignedp32(ptr+1) == U_MULTICHAR_CONSTANT32('F','I','L','E'))
{
UFile file;
char pathname[U_PATH_MAX];
ptr += U_CONSTANT_SIZE("@FILE:");
if (*ptr == '"') ++ptr; // check if string is quoted...
U_INTERNAL_ASSERT_EQUALS(u__isspace(*ptr), false)
for (char* path = pathname; ptr < _pend; ++path, ++ptr)
{
c = *ptr;
if (c == '"' ||
u__isspace(c))
{
if (c == '"') ++ptr;
*path = '\0';
break;
}
*path = c;
}
*p = ptr;
if (file.open(pathname)) *this = file.getContent();
else
{
U_WARNING("Open file %S specified in configuration failed", pathname);
}
U_INTERNAL_DUMP("size = %u, str = %V", size(), rep)
U_INTERNAL_ASSERT(invariant())
return;
}
U_INTERNAL_ASSERT_EQUALS(memcmp(ptr, U_CONSTANT_TO_PARAM("@STRING:")), 0)
ptr += U_CONSTANT_SIZE("@STRING:");
const char* start;
if (*ptr == '"') // check if string is quoted...
{
ptr = u_find_char((start = (ptr+1)), _pend, '"'); // find char '"' not quoted
if (ptr == _pend)
{
(void) append(ptr, _pend - ptr);
*p = _pend;
U_INTERNAL_DUMP("size = %u, str = %V", size(), rep)
U_INTERNAL_ASSERT(invariant())
return;
}
U_INTERNAL_ASSERT_EQUALS(*ptr, '"')
sz = ptr++ - start;
}
else
{
for (start = ptr; ptr < _pend; ++ptr)
{
c = *ptr;
if (u__isspace(c)) break;
}
sz = ptr - start;
}
setBuffer(sz * 4);
UEscape::decode(start, sz, *this);
U_INTERNAL_ASSERT_MAJOR(rep->_length, 0)
*p = ptr;
U_INTERNAL_DUMP("size = %u, str = %V", size(), rep)
U_INTERNAL_ASSERT(invariant())
return;
}
loop:
if ( delim == c ||
(delim != '"' &&
u__isspace(c)) ||
(delim == '\0' &&
(c == '}' ||
c == ']')))
{
++ptr;
goto end;
}
if (c == '\\')
{
c = *++ptr;
U_INTERNAL_DUMP("c (after '\\') = %C", c)
if (c != delim)
{
if (c == '\n')
{
// compress multiple white-space in a single new-line...
U_INTERNAL_DUMP("ptr+1 = %.*S", 20, ptr+1)
while (ptr < _pend)
{
if (u__isspace(ptr[1]) == false) break;
++ptr;
}
U_INTERNAL_DUMP("ptr+1 = %.*S", 20, ptr+1)
}
else if (strchr("nrtbfvae", c))
{
_append('\\');
}
}
}
_append(c);
if (++ptr <= _pend)
{
c = *ptr;
U_INTERNAL_DUMP("c = %C", c)
goto loop;
}
end:
_append();
*p = ptr;
if (empty()) _assign(UStringRep::string_rep_null);
else
{
if (shrink() == false) setNullTerminated();
}
U_INTERNAL_DUMP("size = %u, str = %V", size(), rep)
U_INTERNAL_ASSERT(invariant())
}
// STREAM
#ifdef U_STDCPP_ENABLE
void UString::get(istream& is)
{
U_TRACE(0, "UString::get(%p)", &is)
if (is.peek() != '"') is >> *this;
else
{
(void) is.get(); // skip '"'
(void) getline(is, '"');
}
}
void UStringRep::write(ostream& os) const
{
U_TRACE(0, "UStringRep::write(%p)", &os)
if (needQuote() == false) os.write(str, _length);
else
{
os.put('"');
char* p;
char* s = (char*)str;
char* _end = s + _length;
while (s < _end)
{
p = (char*) memchr(s, '"', _end - s);
if (p == U_NULLPTR)
{
os.write(s, _end - s);
break;
}
os.write(s, p - s);
if (*(p-1) == '\\') os.put('\\');
os.put('\\');
os.put('"');
s = p + 1;
}
os.put('"');
}
}
U_EXPORT istream& operator>>(istream& in, UString& str)
{
U_TRACE(0+256, "UString::operator>>(%p,%p)", &in, &str)
uint32_t extracted = 0;
if (in.good())
{
streambuf* sb = in.rdbuf();
int c = sb->sbumpc();
if (in.flags() & ios::skipws)
{
while ((c != EOF) &&
u__isspace(c))
{
c = sb->sbumpc();
}
}
if (c != EOF)
{
if (str)
{
if (str.uniq()) str.setEmpty();
else str._set(UStringRep::create(0U, U_CAPACITY, U_NULLPTR)); // NB: we need this because we use the same object for all input stream of vector (see vector.h:830)...
}
streamsize w = in.width();
uint32_t n = (w > 0 ? (uint32_t)w
: str.max_size());
while (extracted < n &&
u__isspace(c) == false)
{
str._append(c);
++extracted;
c = sb->sbumpc();
// U_INTERNAL_DUMP("c = %C, EOF = %C", c, EOF)
if (c == EOF) break;
}
str._append();
}
if (c == EOF) in.setstate(ios::eofbit);
else sb->sputbackc(c);
in.width(0);
U_INTERNAL_DUMP("size = %u, str = %V", str.size(), str.rep)
}
if (extracted == 0) in.setstate(ios::failbit);
else if (str.shrink() == false) str.setNullTerminated();
U_INTERNAL_ASSERT(str.invariant())
return in;
}
istream& UString::getline(istream& in, unsigned char delim)
{
U_TRACE(0+256, "UString::getline(%p,%C)", &in, delim)
int c = EOF;
bool extracted = false;
if (in.good())
{
if (size())
{
if (uniq()) setEmpty();
else _set(UStringRep::create(0U, U_CAPACITY, U_NULLPTR)); // NB: we need this because we use the same object for all input stream of vector (see vector.h:830)...
}
streambuf* sb = in.rdbuf();
while (true)
{
c = sb->sbumpc();
U_INTERNAL_DUMP("c = %C", c)
if (c == '\\')
{
c = sb->sbumpc();
U_INTERNAL_DUMP("c = %C", c)
if (c == delim)
{
_append(delim);
continue;
}
if (strchr("nrt\nbfvae", c))
{
if (c != '\n') _append('\\');
else
{
// compress multiple white-space in a single new-line...
do { c = sb->sbumpc(); } while (c != EOF && u__isspace(c));
if (c != EOF)
{
sb->sputbackc(c);
c = '\n';
}
}
}
}
if (c == EOF)
{
in.setstate(ios::eofbit);
break;
}
if (c == delim) break;
_append(c);
}
_append();
U_INTERNAL_DUMP("size = %u, str = %V", size(), rep)
extracted = (empty() == false);
if (extracted &&
shrink() == false)
{
setNullTerminated();
}
}
if (c != delim &&
extracted == false)
{
in.setstate(ios::failbit);
}
U_INTERNAL_ASSERT(invariant())
return in;
}
U_EXPORT ostream& operator<<(ostream& out, const UString& str)
{
U_TRACE(0, "UString::operator<<(%p,%p)", &out, &str)
if (out.good())
{
const char* s = str.data();
streamsize res,
w = out.width(),
len = (streamsize)str.size();
if (w <= len) res = out.rdbuf()->sputn(s, len);
else
{
int plen = (int)(w - len);
ios::fmtflags fmt = (out.flags() & ios::adjustfield);
if (fmt == ios::left)
{
res = out.rdbuf()->sputn(s, len);
// Padding last
for (int i = 0; i < plen; ++i) (void) out.rdbuf()->sputc(' ');
}
else
{
// Padding first
for (int i = 0; i < plen; ++i) (void) out.rdbuf()->sputc(' ');
res = out.rdbuf()->sputn(s, len);
}
}
U_INTERNAL_DUMP("len = %u, res = %u, w = %u", len, res, w)
out.width(0);
if (res != len) out.setstate(ios::failbit);
}
return out;
}
#endif
// operator +
U_EXPORT UString operator+(const UString& lhs, const UString& rhs)
{
uint32_t sz1 = lhs.size(),
sz2 = rhs.size();
UString str(sz1 + sz2);
(void) str.append(lhs.data(), sz1);
(void) str.append(rhs.data(), sz2);
return str;
}
U_EXPORT UString operator+(const UString& lhs, const char* rhs)
{
uint32_t sz1 = lhs.size(),
sz2 = u__strlen(rhs, __PRETTY_FUNCTION__);
UString str(sz1 + sz2);
(void) str.append(lhs.data(), sz1);
(void) str.append(rhs, sz2);
return str;
}
U_EXPORT UString operator+(const char* lhs, const UString& rhs)
{
uint32_t sz2 = rhs.size(),
sz1 = u__strlen(lhs, __PRETTY_FUNCTION__);
UString str(sz1 + sz2);
(void) str.append(lhs, sz1);
(void) str.append(rhs.data(), sz2);
return str;
}
U_EXPORT UString operator+(const UString& lhs, char rhs)
{
uint32_t sz = lhs.size();
UString str(sz + 1U);
(void) str.append(lhs.data(), sz);
(void) str.append(1U, rhs);
return str;
}
U_EXPORT UString operator+(char lhs, const UString& rhs)
{
uint32_t sz = rhs.size();
UString str(sz + 1U);
(void) str.append(1U, lhs);
(void) str.append(rhs.data(), sz);
return str;
}
#ifdef DEBUG
const char* UStringRep::dump(bool reset) const
{
#ifdef U_STDCPP_ENABLE
*UObjectIO::os << "length " << _length << '\n'
<< "capacity " << _capacity << '\n'
<< "references " << references << '\n'
<< "parent " << (void*)parent << '\n'
<< "child " << child << '\n'
<< "str " << (void*)str << ' ';
char buffer[1024];
UObjectIO::os->write(buffer, u__snprintf(buffer, sizeof(buffer), U_CONSTANT_TO_PARAM("%V"), this));
if (reset)
{
UObjectIO::output();
return UObjectIO::buffer_output;
}
#endif
return U_NULLPTR;
}
bool UStringRep::invariant() const
{
if (_capacity &&
_capacity < _length)
{
U_WARNING("Error on rep string: (overflow)\n"
"--------------------------------------------------\n%s", UStringRep::dump(true));
return false;
}
if ((int32_t)references < 0)
{
U_WARNING("Error on rep string: (leak reference)\n"
"--------------------------------------------------\n%s", UStringRep::dump(true));
return false;
}
if (this == string_rep_null)
{
U_CHECK_MEMORY
if (_length)
{
U_WARNING("Error on string_rep_null: (not empty)\n"
"--------------------------------------------------\n%s", UStringRep::dump(true));
return false;
}
return true;
}
return string_rep_null->invariant();
}
bool UString::invariant() const
{
if (rep == U_NULLPTR)
{
U_WARNING("Error on string: (rep = null pointer)");
return false;
}
return rep->invariant();
}
void UString::vsnprintf_check(const char* format) const
{
bool ok_writeable = writeable(),
ok_isNull = (isNull() == false),
ok_references = (rep->references == 0),
ok_format = (rep->_capacity > u__strlen(format, __PRETTY_FUNCTION__));
if (ok_writeable == false ||
ok_isNull == false ||
ok_format == false)
{
// -----------------------------------------------------------------------------------------------------------------------------------------
// Ex: userver_tcp: ERROR: UString::vsnprintf_check() this = 0xa79bbd18 parent = (nil) references = 2126 child = 0 _capacity = 0 str(0) = ""
// format = "%v:" - ok_writeable = false ok_isNull = false ok_references = false ok_format = false
// -----------------------------------------------------------------------------------------------------------------------------------------
U_ERROR("UString::vsnprintf_check() this = %p parent = %p rep = %p references = %u child = %d _capacity = %u str(%u) = %V format = %S - "
"ok_writeable = %b ok_isNull = %b ok_references = %b ok_format = %b",
this, rep->parent, rep, rep->references, rep->child, rep->_capacity, rep->_length, rep, format, ok_writeable, ok_isNull, ok_references, ok_format);
}
else if (ok_references == false)
{
U_WARNING("UString::vsnprintf_check() this = %p parent = %p rep = %p references = %u child = %d _capacity = %u str(%u) = %V format = %S - "
"ok_writeable = %b ok_isNull = %b ok_references = %b ok_format = %b",
this, rep->parent, rep, rep->references, rep->child, rep->_capacity, rep->_length, rep, format, ok_writeable, ok_isNull, ok_references, ok_format);
}
}
#endif
#if defined(U_STDCPP_ENABLE) && defined(DEBUG)
const char* UString::dump(bool reset) const
{
U_CHECK_MEMORY_OBJECT(rep)
*UObjectIO::os << "rep (UStringRep " << (void*)rep << ")";
if (rep == rep->string_rep_null) UObjectIO::os->write(U_CONSTANT_TO_PARAM(" == UStringRep::string_rep_null"));
if (reset)
{
UObjectIO::output();
return UObjectIO::buffer_output;
}
return U_NULLPTR;
}
#endif