--- parser3/src/include/pa_string.h 2015/10/08 22:49:36 1.212 +++ parser3/src/include/pa_string.h 2017/12/05 22:59:58 1.224 @@ -1,14 +1,14 @@ /** @file Parser: string class decl. - Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com) + Copyright (c) 2001-2017 Art. Lebedev Studio (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) */ #ifndef PA_STRING_H #define PA_STRING_H -#define IDENT_PA_STRING_H "$Id: pa_string.h,v 1.212 2015/10/08 22:49:36 moko Exp $" +#define IDENT_PA_STRING_H "$Id: pa_string.h,v 1.224 2017/12/05 22:59:58 moko Exp $" // includes #include "pa_types.h" @@ -16,7 +16,7 @@ extern "C" { // cord's author forgot to do that #define CORD_NO_IO -#include "cord.h" +#include "../lib/cord/include/cord.h" #ifdef CORD_CAT_OPTIMIZATION #define CORD_cat(x, y) CORD_cat_optimized(x, y) @@ -73,6 +73,7 @@ unsigned long long int pa_atoul(const ch class String: public PA_Object { + friend class StringSplitHelper; public: /** piece is tainted or not. the lang to use when detaint @@ -95,11 +96,6 @@ public: L_CLEAN='0', ///< clean WARNING: read above warning before changing L_AS_IS='A', ///< leave all characters intact WARNING: read above warning before changing - L_PASS_APPENDED='P', - /**< - leave lang built into string being appended. - just a flag, that value not stored - */ L_TAINTED='T', ///< tainted, untaint lang as assigned later // untaint langs. assigned by ^untaint[lang]{...} L_FILE_SPEC='F', ///< file specification @@ -175,7 +171,7 @@ public: public: - const char* v() const; + const char* visualize() const; void dump() const; Languages(): langs(0) {} @@ -311,6 +307,22 @@ public: } }; + struct C { + const char *str; + size_t length; + C(): str(0), length(0) {} + C(const char *astr, size_t asize): str(astr), length(asize) {} + explicit C(Body abody): str(abody.cstr()), length(abody.length()) {} + }; + + struct Cm { + char *str; + size_t length; + Cm(): str(0), length(0) {} + Cm(char *astr, size_t asize): str(astr), length(asize) {} + explicit Cm(Body abody): str(abody.cstrm()), length(abody.length()) {} + }; + class Body { CORD body; @@ -319,33 +331,32 @@ public: // cached hash code is not reseted on write operations as test shows // that string body does not change after it is stored as a hash key mutable uint hash_code; +#define INIT_HASH_CODE(c) ,hash_code(c) +#define ZERO_HASH_CODE hash_code=0; +#else +#define INIT_HASH_CODE(c) +#define ZERO_HASH_CODE #endif #ifdef STRING_LENGTH_CACHING // cached length is reseted on modification, used only for char*, not CORD mutable size_t string_length; -#define INIT_LENGTH ,string_length(0) +#define INIT_LENGTH(l) ,string_length(l) #define ZERO_LENGTH string_length=0; #else -#define INIT_LENGTH +#define INIT_LENGTH(l) #define ZERO_LENGTH #endif public: - const char* v() const; void dump() const; -#ifdef HASH_CODE_CACHING - Body(): body(CORD_EMPTY), hash_code(0) INIT_LENGTH {} - Body(CORD abody, uint ahash_code): body(abody), hash_code(ahash_code) INIT_LENGTH {} - Body(const char *abody): body(AS_CORD(abody)), hash_code(0) INIT_LENGTH {} - explicit Body(CORD abody): body(abody), hash_code(0) INIT_LENGTH { -#else - Body(): body(CORD_EMPTY) INIT_LENGTH {} - Body(const char *abody): body(AS_CORD(abody)) INIT_LENGTH {} - explicit Body(CORD abody): body(abody) INIT_LENGTH { -#endif + Body(): body(CORD_EMPTY) INIT_HASH_CODE(0) INIT_LENGTH(0) {} + Body(const char *abody): body(AS_CORD(abody)) INIT_HASH_CODE(0) INIT_LENGTH(0) {} + Body(CORD abody, uint ahash_code): body(abody) INIT_HASH_CODE(ahash_code) INIT_LENGTH(0) {} + explicit Body(C ac): body(AS_CORD(ac.str)) INIT_HASH_CODE(0) INIT_LENGTH(ac.length) {} + explicit Body(CORD abody): body(abody) INIT_HASH_CODE(0) INIT_LENGTH(0) { #ifdef CORD_CAT_OPTIMIZATION assert(!body // no body || *body // ordinary string @@ -364,15 +375,17 @@ public: #endif } + static Body Format(int value); - void clear() { ZERO_LENGTH body=CORD_EMPTY; } + void clear() { ZERO_LENGTH ZERO_HASH_CODE body=CORD_EMPTY; } bool operator! () const { return is_empty(); } inline CORD get_cord() const { return body; } uint get_hash_code() const; + // never null const char* cstr() const { #ifdef STRING_LENGTH_CACHING string_length = length(); @@ -385,6 +398,7 @@ public: return CORD_to_const_char_star(body, length()); } + // never null char* cstrm() const { return CORD_to_char_star(body, length()); } #ifdef STRING_LENGTH_CACHING @@ -471,26 +485,11 @@ public: size_t* out_start=0, size_t* out_length=0, Charset* source_charset=0) const; }; - struct C { - const char *str; - size_t length; - C(): str(0), length(0) {} - C(const char *astr, size_t asize): str(astr), length(asize) {} - }; - - struct Cm { - char *str; - size_t length; - Cm(): str(0), length(0) {} - Cm(char *astr, size_t asize): str(astr), length(asize) {} - }; - private: Body body; ///< all characters of string Languages langs; ///< string characters lang - const char* v() const; void dump() const; #define ASSERT_STRING_INVARIANT(string) \ assert((string).langs.invariant((string).body.length())) @@ -505,11 +504,8 @@ public: langs=alang; } } - explicit String(C ac, Language alang=L_CLEAN) : body(ac.str){ + explicit String(C ac, Language alang=L_CLEAN) : body(ac){ if(body.get_cord()){ -#ifdef STRING_LENGTH_CACHING - body.set_length(ac.length); -#endif langs=alang; } } @@ -567,6 +563,8 @@ public: return langs.opt.lang; } + char* visualize_langs() const; + /// puts pieces to buf Cm serialize(size_t prolog_size) const; /// appends pieces from buf to self @@ -589,6 +587,7 @@ public: return Body(x).ncmp(0/*x_begin*/, body, 0/*y_begin*/, length())==0; } + String& append_to(String& dest) const; String& append_to(String& dest, Language lang, bool forced=false) const; String& append(const String& src, Language lang, bool forced=false) { return src.append_to(*this, lang, forced); @@ -601,7 +600,7 @@ public: return *this; } - String& operator << (const String& src) { return append(src, L_PASS_APPENDED); } + String& operator << (const String& src) { return src.append_to(*this); } String& operator << (const char* src) { return append_help_length(src, 0, L_AS_IS); } String& operator << (const Body& src){ langs.appendHelper(body, L_AS_IS, src); @@ -633,18 +632,13 @@ public: but when specified: look for substring that lies in ONE fragment in THAT lang @return position of substr in string, -1 means "not found" [const char* version] */ - size_t pos(const Body substr, - size_t this_offset=0, Language lang=L_UNSPECIFIED) const; + size_t pos(const Body substr, size_t this_offset=0, Language lang=L_UNSPECIFIED) const; /// String version of @see pos(const char*, int, Language) - size_t pos(const String& substr, - size_t this_offset=0, Language lang=L_UNSPECIFIED) const; - size_t pos(char c, - size_t this_offset=0) const { + size_t pos(const String& substr, size_t this_offset=0, Language lang=L_UNSPECIFIED) const; + size_t pos(char c, size_t this_offset=0) const { return body.pos(c, this_offset); } - size_t pos(Charset& charset, - const String& substr, - size_t this_offset=0, Language lang=L_UNSPECIFIED) const; + size_t pos(Charset& charset, const String& substr, size_t this_offset=0, Language lang=L_UNSPECIFIED) const; size_t strrpbrk(const char* chars, size_t left=0) const { return (length()) ? body.strrpbrk(chars, left, length()-1) : STRING_NOT_FOUND; @@ -660,19 +654,11 @@ public: return body.rskipchars(chars, left, right); } - void split(ArrayString& result, - size_t& pos_after, - const char* delim, - Language lang=L_UNSPECIFIED, int limit=-1) const; - void split(ArrayString& result, - size_t& pos_after, - const String& delim, - Language lang=L_UNSPECIFIED, int limit=-1) const; - - typedef void (*Row_action)(Table& table, ArrayString* row, - int prestart, int prefinish, - int poststart, int postfinish, - void *info); + void split(ArrayString& result, size_t pos_after, const char* delim, Language lang=L_UNSPECIFIED) const; + void split(ArrayString& result, size_t pos_after, const String& delim, Language lang=L_UNSPECIFIED) const; + + typedef void (*Row_action)(Table& table, ArrayString* row, int prestart, int prefinish, int poststart, int postfinish, void *info); + /** @return table of found items, if any. table format is defined and fixed[can be used by others]: @@ -680,15 +666,14 @@ public: prematch/match/postmatch/1/2/3/... @endverbatim */ - Table* match(VRegex* vregex, - Row_action row_action, void *info, - int& matches_count) const; + Table* match(VRegex* vregex, Row_action row_action, void *info, int& matches_count) const; + enum Change_case_kind { CC_UPPER, CC_LOWER }; - String& change_case(Charset& source_charset, - Change_case_kind kind) const; + String& change_case(Charset& source_charset, Change_case_kind kind) const; + const String& replace(const Dictionary& dict) const; const String& trim(Trim_kind kind=TRIM_BOTH, const char* chars=0, Charset* source_charset=0) const; double as_double() const { return pa_atod(cstr(), this); }