diff --git a/src/pugixml.cpp b/src/pugixml.cpp index ee8a666..f316b29 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -436,12 +436,14 @@ PUGI__NS_BEGIN #endif // extra metadata bits + static const uintptr_t xml_memory_page_contents_const_mask = 128; static const uintptr_t xml_memory_page_contents_shared_mask = 64; static const uintptr_t xml_memory_page_name_allocated_mask = 32; static const uintptr_t xml_memory_page_value_allocated_mask = 16; static const uintptr_t xml_memory_page_type_mask = 15; // combined masks for string uniqueness + static const uintptr_t xml_memory_page_contents_const_or_shared_mask = xml_memory_page_contents_const_mask | xml_memory_page_contents_shared_mask; static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask; static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask; @@ -1055,7 +1057,27 @@ namespace pugi { xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), namevalue_base(0) { - PUGI__STATIC_ASSERT(sizeof(xml_attribute_struct) == 8); + PUGI__STATIC_ASSERT(sizeof(xml_attribute_struct) == 8 + 8); + } + + inline string_view_t unsafe_name_sv() const { + return string_view_t(name, name_len); + } + + inline string_view_t unsafe_value_sv() const { + return string_view_t(value, value_len); + } + + inline string_view_t value_sv() const { + return value ? unsafe_value_sv() : PUGIXML_EMPTY_SV; + } + + inline bool equals_name(string_view_t rhs) const { + return name && unsafe_name_sv() == rhs; + } + + inline bool equals_value(string_view_t rhs) const { + return value_sv() == rhs; } impl::compact_header header; @@ -1067,13 +1089,32 @@ namespace pugi impl::compact_pointer prev_attribute_c; impl::compact_pointer next_attribute; + + int name_len; + int value_len; }; struct xml_node_struct { xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type), namevalue_base(0) { - PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12); + PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12 + 8); + } + + inline string_view_t unsafe_name_sv() const { + return string_view_t(name, name_len); + } + + inline string_view_t unsafe_value_sv() const { + return string_view_t(value, value_len); + } + + inline string_view_t value_sv() const { + return value ? unsafe_value_sv() : PUGIXML_EMPTY_SV; + } + + inline bool equals_name(string_view_t rhs) const { + return name && unsafe_name_sv() == rhs; } impl::compact_header header; @@ -1091,6 +1132,9 @@ namespace pugi impl::compact_pointer next_sibling; impl::compact_pointer first_attribute; + + int name_len; + int value_len; }; } #else @@ -1103,11 +1147,34 @@ namespace pugi header = PUGI__GETHEADER_IMPL(this, page, 0); } + inline string_view_t unsafe_name_sv() const { + return string_view_t(name, name_len); + } + + inline string_view_t unsafe_value_sv() const { + return string_view_t(value, value_len); + } + + inline string_view_t value_sv() const { + return value ? unsafe_value_sv() : PUGIXML_EMPTY_SV; + } + + inline bool equals_name(string_view_t rhs) const { + return name && unsafe_name_sv() == rhs; + } + + inline bool equals_value(string_view_t rhs) const { + return value_sv() == rhs; + } + uintptr_t header; char_t* name; char_t* value; + int name_len; + int value_len; + xml_attribute_struct* prev_attribute_c; xml_attribute_struct* next_attribute; }; @@ -1119,10 +1186,28 @@ namespace pugi header = PUGI__GETHEADER_IMPL(this, page, type); } + inline string_view_t unsafe_name_sv() const { + return string_view_t(name, name_len); + } + + inline string_view_t unsafe_value_sv() const { + return string_view_t(value, value_len); + } + + inline string_view_t value_sv() const { + return value ? unsafe_value_sv() : PUGIXML_EMPTY_SV; + } + + inline bool equals_name(string_view_t rhs) const { + return name && unsafe_name_sv() == rhs; + } + uintptr_t header; char_t* name; char_t* value; + int name_len; + int value_len; xml_node_struct* parent; @@ -2358,7 +2443,7 @@ PUGI__NS_BEGIN inline bool strcpy_insitu_allow(size_t length, const Header& header, uintptr_t header_mask, char_t* target) { // never reuse shared memory - if (header & xml_memory_page_contents_shared_mask) return false; + if (header & xml_memory_page_contents_const_or_shared_mask) return false; size_t target_length = strlength(target); @@ -2372,9 +2457,11 @@ PUGI__NS_BEGIN } template - PUGI__FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length) + PUGI__FN bool strcpy_insitu(String& dest, int& dest_len, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length, boolean shallow_copy = pugi::false_value) { - if (source_length == 0) + dest_len = static_cast(source_length); + + if (source_length == 0 || shallow_copy) { // empty string and null pointer are equivalent, so just deallocate old memory xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator; @@ -2382,16 +2469,19 @@ PUGI__NS_BEGIN if (header & header_mask) alloc->deallocate_string(dest); // mark the string as not allocated - dest = 0; + dest = source_length == 0 ? NULL : const_cast(source); header &= ~header_mask; + // mark dest as shared to avoid reuse document buffer memory + header |= xml_memory_page_contents_const_mask; + return true; } else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest)) { // we can reuse old buffer, so just copy the new data (including zero terminator) memcpy(dest, source, source_length * sizeof(char_t)); - dest[source_length] = 0; + dest[source_length] = '\0'; return true; } @@ -2407,7 +2497,7 @@ PUGI__NS_BEGIN // copy the string (including zero terminator) memcpy(buf, source, source_length * sizeof(char_t)); - buf[source_length] = 0; + buf[source_length] = '\0'; // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) if (header & header_mask) alloc->deallocate_string(dest); @@ -2416,6 +2506,9 @@ PUGI__NS_BEGIN dest = buf; header |= header_mask; + // remove dest shared mask for continue reuse document buffer memory + header &= ~xml_memory_page_contents_const_mask; + return true; } } @@ -2611,14 +2704,16 @@ PUGI__NS_BEGIN #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; } #define PUGI__SCANWHILE(X) { while (X) ++s; } #define PUGI__SCANWHILE_UNROLL(X) { for (;;) { char_t ss = s[0]; if (PUGI__UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI__UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI__UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI__UNLIKELY(!(X))) { s += 3; break; } s += 4; } } - #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; } + #define PUGI__ENDSEG(p,v) { ch = *s; p->v##_len = static_cast(s - p->v); *s = '\0'; ++s; } #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast(0) #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); } - PUGI__FN char_t* strconv_comment(char_t* s, char_t endch) + PUGI__FN char_t* strconv_comment(char_t* s, char_t endch, int& len) { gap g; + char_t* begin = s; + while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment)); @@ -2631,7 +2726,9 @@ PUGI__NS_BEGIN } else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here { - *g.flush(s) = 0; + char_t* end = g.flush(s); + *end = '\0'; + len = static_cast(end - begin); return s + (s[2] == '>' ? 3 : 2); } @@ -2643,10 +2740,12 @@ PUGI__NS_BEGIN } } - PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch) + PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch, int& len) { gap g; + char_t* begin = s; + while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata)); @@ -2659,7 +2758,9 @@ PUGI__NS_BEGIN } else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here { - *g.flush(s) = 0; + char_t* end = g.flush(s); + *end = '\0'; + len = static_cast(end - begin); return s + 1; } @@ -2671,11 +2772,11 @@ PUGI__NS_BEGIN } } - typedef char_t* (*strconv_pcdata_t)(char_t*); + typedef char_t* (*strconv_pcdata_t)(char_t*, int& len); template struct strconv_pcdata_impl { - static char_t* parse(char_t* s) + static char_t* parse(char_t* s, int& len) { gap g; @@ -2693,7 +2794,8 @@ PUGI__NS_BEGIN while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) --end; - *end = 0; + *end = '\0'; + len = static_cast(end - begin); return s + 1; } @@ -2715,7 +2817,8 @@ PUGI__NS_BEGIN while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) --end; - *end = 0; + *end = '\0'; + len = static_cast(end - begin); return s; } @@ -2742,14 +2845,16 @@ PUGI__NS_BEGIN } } - typedef char_t* (*strconv_attribute_t)(char_t*, char_t); + typedef char_t* (*strconv_attribute_t)(char_t*, char_t, int& len); template struct strconv_attribute_impl { - static char_t* parse_wnorm(char_t* s, char_t end_quote) + static char_t* parse_wnorm(char_t* s, char_t end_quote, int& len) { gap g; + char_t* begin = s; + // trim leading whitespaces if (PUGI__IS_CHARTYPE(*s, ct_space)) { @@ -2769,9 +2874,11 @@ PUGI__NS_BEGIN { char_t* str = g.flush(s); - do *str-- = 0; + do *str-- = '\0'; while (PUGI__IS_CHARTYPE(*str, ct_space)); + len = static_cast(str + 1 - begin); + return s + 1; } else if (PUGI__IS_CHARTYPE(*s, ct_space)) @@ -2798,17 +2905,21 @@ PUGI__NS_BEGIN } } - static char_t* parse_wconv(char_t* s, char_t end_quote) + static char_t* parse_wconv(char_t* s, char_t end_quote, int& len) { gap g; + char_t* begin = s; + while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws)); if (*s == end_quote) { - *g.flush(s) = 0; + char_t* end = g.flush(s); + *end = '\0'; + len = static_cast(end - begin); return s + 1; } @@ -2834,17 +2945,21 @@ PUGI__NS_BEGIN } } - static char_t* parse_eol(char_t* s, char_t end_quote) + static char_t* parse_eol(char_t* s, char_t end_quote, int& len) { gap g; + char_t* begin = s; + while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); if (*s == end_quote) { - *g.flush(s) = 0; + char_t* end = g.flush(s); + *end = '\0'; + len = static_cast(end - begin); return s + 1; } @@ -2866,17 +2981,21 @@ PUGI__NS_BEGIN } } - static char_t* parse_simple(char_t* s, char_t end_quote) + static char_t* parse_simple(char_t* s, char_t end_quote, int& len) { gap g; + char_t* begin = s; + while (true) { PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); if (*s == end_quote) { - *g.flush(s) = 0; + char_t* end = g.flush(s); + *end = '\0'; + len = static_cast(end - begin); return s + 1; } @@ -3076,7 +3195,7 @@ PUGI__NS_BEGIN if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments)) { - s = strconv_comment(s, endch); + s = strconv_comment(s, endch, cursor->value_len); if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value); } @@ -3086,9 +3205,10 @@ PUGI__NS_BEGIN PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')); PUGI__CHECK_ERROR(status_bad_comment, s); - if (PUGI__OPTSET(parse_comments)) - *s = 0; // Zero-terminate this segment at the first terminating '-'. - + if (PUGI__OPTSET(parse_comments)) { + *s = '\0'; // Zero-terminate this segment at the first terminating '-'. + cursor->value_len = static_cast(s - cursor->value); + } s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'. } } @@ -3108,7 +3228,7 @@ PUGI__NS_BEGIN if (PUGI__OPTSET(parse_eol)) { - s = strconv_cdata(s, endch); + s = strconv_cdata(s, endch, cursor->value_len); if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value); } @@ -3118,7 +3238,8 @@ PUGI__NS_BEGIN PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')); PUGI__CHECK_ERROR(status_bad_cdata, s); - *s++ = 0; // Zero-terminate this segment. + cursor->value_len = static_cast(s - cursor->value); + *s++ = '\0'; // Zero-terminate this segment. } } else // Flagged for discard, but we still have to scan for the terminator. @@ -3146,7 +3267,7 @@ PUGI__NS_BEGIN if (!s) return s; assert((*s == 0 && endch == '>') || *s == '>'); - if (*s) *s++ = 0; + if (*s) *s++ = '\0'; if (PUGI__OPTSET(parse_doctype)) { @@ -3155,6 +3276,7 @@ PUGI__NS_BEGIN PUGI__PUSHNODE(node_doctype); cursor->value = mark; + cursor->value_len = static_cast(s - mark - 1); } } else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s); @@ -3200,7 +3322,7 @@ PUGI__NS_BEGIN cursor->name = target; - PUGI__ENDSEG(); + PUGI__ENDSEG(cursor, name); // parse value/attributes if (ch == '?') @@ -3233,11 +3355,9 @@ PUGI__NS_BEGIN { // store value and step over > cursor->value = value; - + PUGI__ENDSEG(cursor, value); PUGI__POPNODE(); - PUGI__ENDSEG(); - s += (*s == '>'); } } @@ -3281,7 +3401,7 @@ PUGI__NS_BEGIN cursor->name = s; PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. - PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. + PUGI__ENDSEG(cursor, name); // Save char in 'ch', terminate & step over. if (ch == '>') { @@ -3302,7 +3422,7 @@ PUGI__NS_BEGIN a->name = s; // Save the offset. PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. - PUGI__ENDSEG(); // Save char in 'ch', terminate & step over. + PUGI__ENDSEG(a, name); // Save char in 'ch', terminate & step over. if (PUGI__IS_CHARTYPE(ch, ct_space)) { @@ -3322,7 +3442,7 @@ PUGI__NS_BEGIN ++s; // Step over the quote. a->value = s; // Save the offset. - s = strconv_attribute(s, ch); + s = strconv_attribute(s, ch, a->value_len); if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value); @@ -3460,20 +3580,22 @@ PUGI__NS_BEGIN if (cursor->parent || PUGI__OPTSET(parse_fragment)) { + pugi::xml_node_struct* target; if (PUGI__OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value) { - cursor->value = s; // Save the offset. + target = cursor; // cursor->value = s; // Save the offset. } else { PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree. - cursor->value = s; // Save the offset. + target = cursor; // cursor->value = s; // Save the offset. PUGI__POPNODE(); // Pop since this is a standalone. } - s = strconv_pcdata(s); + target->value = s; + s = strconv_pcdata(s, target->value_len); if (!*s) break; } @@ -4406,7 +4528,7 @@ PUGI__NS_BEGIN } template - PUGI__FN void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc) + PUGI__FN void node_copy_string(String& dest, int& dest_len, Header& header, uintptr_t header_mask, char_t* source, int source_len, Header& source_header, xml_allocator* alloc) { assert(!dest && (header & header_mask) == 0); @@ -4415,20 +4537,21 @@ PUGI__NS_BEGIN if (alloc && (source_header & header_mask) == 0) { dest = source; + dest_len = source_len; // since strcpy_insitu can reuse document buffer memory we need to mark both source and dest as shared header |= xml_memory_page_contents_shared_mask; source_header |= xml_memory_page_contents_shared_mask; } else - strcpy_insitu(dest, header, header_mask, source, strlength(source)); + strcpy_insitu(dest, dest_len, header, header_mask, source, source_len); } } PUGI__FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc) { - node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc); - node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc); + node_copy_string(dn->name, dn->name_len, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->name_len, sn->header, shared_alloc); + node_copy_string(dn->value, dn->value_len, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->value_len, sn->header, shared_alloc); for (xml_attribute_struct* sa = sn->first_attribute; sa; sa = sa->next_attribute) { @@ -4436,8 +4559,8 @@ PUGI__NS_BEGIN if (da) { - node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); - node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); + node_copy_string(da->name, da->name_len, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->name_len, sa->header, shared_alloc); + node_copy_string(da->value, da->value_len, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->value_len, sa->header, shared_alloc); } } } @@ -4501,8 +4624,8 @@ PUGI__NS_BEGIN xml_allocator& alloc = get_allocator(da); xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : 0; - node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc); - node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc); + node_copy_string(da->name, da->name_len, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->name_len, sa->header, shared_alloc); + node_copy_string(da->value, da->value_len, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->value_len, sa->header, shared_alloc); } inline bool is_text_node(xml_node_struct* node) @@ -4666,53 +4789,54 @@ PUGI__NS_BEGIN // set value with conversion functions template - PUGI__FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf) + PUGI__FN bool set_value_ascii(String& dest, int& dest_len, Header& header, uintptr_t header_mask, char* buf, size_t len) { #ifdef PUGIXML_WCHAR_MODE + (void)len; char_t wbuf[128]; - assert(strlen(buf) < sizeof(wbuf) / sizeof(wbuf[0])); + assert(len < sizeof(wbuf) / sizeof(wbuf[0])); size_t offset = 0; for (; buf[offset]; ++offset) wbuf[offset] = buf[offset]; - return strcpy_insitu(dest, header, header_mask, wbuf, offset); + return strcpy_insitu(dest, dest_len, header, header_mask, wbuf, offset); #else - return strcpy_insitu(dest, header, header_mask, buf, strlen(buf)); + return strcpy_insitu(dest, dest_len, header, header_mask, buf, len); #endif } template - PUGI__FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative) + PUGI__FN bool set_value_integer(String& dest, int& dest_len, Header& header, uintptr_t header_mask, U value, bool negative) { char_t buf[64]; char_t* end = buf + sizeof(buf) / sizeof(buf[0]); char_t* begin = integer_to_string(buf, end, value, negative); - return strcpy_insitu(dest, header, header_mask, begin, end - begin); + return strcpy_insitu(dest, dest_len, header, header_mask, begin, end - begin); } template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value, int precision) + PUGI__FN bool set_value_convert(String& dest, int& dest_len, Header& header, uintptr_t header_mask, float value, int precision) { char buf[128]; - PUGI__SNPRINTF(buf, "%.*g", precision, double(value)); + int n = PUGI__SNPRINTF(buf, "%.*g", precision, double(value)); - return set_value_ascii(dest, header, header_mask, buf); + return set_value_ascii(dest, dest_len, header, header_mask, buf, n); } template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value, int precision) + PUGI__FN bool set_value_convert(String& dest, int& dest_len, Header& header, uintptr_t header_mask, double value, int precision) { char buf[128]; - PUGI__SNPRINTF(buf, "%.*g", precision, value); + int n = PUGI__SNPRINTF(buf, "%.*g", precision, value); - return set_value_ascii(dest, header, header_mask, buf); + return set_value_ascii(dest, dest_len, header, header_mask, buf, n); } template - PUGI__FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value) + PUGI__FN bool set_value_bool(String& dest, int& dest_len, Header& header, uintptr_t header_mask, bool value) { - return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5); + return strcpy_insitu(dest, dest_len, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5, true_value); } PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) @@ -5218,11 +5342,9 @@ namespace pugi return prev->next_attribute ? xml_attribute(prev) : xml_attribute(); } - PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const + PUGI__FN string_view_t xml_attribute::as_string(string_view_t def) const { - if (!_attr) return def; - const char_t* value = _attr->value; - return value ? value : def; + return (_attr && _attr->value) ? _attr->unsafe_value_sv() : def; } PUGI__FN int xml_attribute::as_int(int def) const @@ -5281,18 +5403,14 @@ namespace pugi return !_attr; } - PUGI__FN const char_t* xml_attribute::name() const + PUGI__FN string_view_t xml_attribute::name() const { - if (!_attr) return PUGIXML_TEXT(""); - const char_t* name = _attr->name; - return name ? name : PUGIXML_TEXT(""); + return (_attr && _attr->name) ? _attr->unsafe_name_sv() : PUGIXML_EMPTY_SV; } - PUGI__FN const char_t* xml_attribute::value() const + PUGI__FN string_view_t xml_attribute::value() const { - if (!_attr) return PUGIXML_TEXT(""); - const char_t* value = _attr->value; - return value ? value : PUGIXML_TEXT(""); + return (_attr && _attr->value) ? _attr->unsafe_value_sv() : PUGIXML_EMPTY_SV; } PUGI__FN size_t xml_attribute::hash_value() const @@ -5305,7 +5423,7 @@ namespace pugi return _attr; } - PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs) + PUGI__FN xml_attribute& xml_attribute::operator=(string_view_t rhs) { set_value(rhs); return *this; @@ -5347,7 +5465,7 @@ namespace pugi return *this; } - PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs) + PUGI__FN xml_attribute& xml_attribute::operator=(boolean rhs) { set_value(rhs); return *this; @@ -5367,88 +5485,86 @@ namespace pugi } #endif - PUGI__FN bool xml_attribute::set_name(const char_t* rhs) + PUGI__FN bool xml_attribute::set_name(string_view_t rhs, boolean shallow_copy) { if (!_attr) return false; - return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); + return impl::strcpy_insitu(_attr->name, _attr->name_len, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.length(), shallow_copy); + } + + PUGI__FN bool xml_attribute::set_value(string_view_t rhs, boolean shallow_copy) + { + if (!_attr) return false; + + return impl::strcpy_insitu(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length(), shallow_copy); } PUGI__FN bool xml_attribute::set_value(const char_t* rhs, size_t sz) { - if (!_attr) return false; - - return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, sz); - } - - PUGI__FN bool xml_attribute::set_value(const char_t* rhs) - { - if (!_attr) return false; - - return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); + return set_value(string_view_t(rhs, sz )); } PUGI__FN bool xml_attribute::set_value(int rhs) { if (!_attr) return false; - return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); + return impl::set_value_integer(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI__FN bool xml_attribute::set_value(unsigned int rhs) { if (!_attr) return false; - return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); + return impl::set_value_integer(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } PUGI__FN bool xml_attribute::set_value(long rhs) { if (!_attr) return false; - return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); + return impl::set_value_integer(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI__FN bool xml_attribute::set_value(unsigned long rhs) { if (!_attr) return false; - return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); + return impl::set_value_integer(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } PUGI__FN bool xml_attribute::set_value(double rhs) { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision); + return impl::set_value_convert(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision); } PUGI__FN bool xml_attribute::set_value(double rhs, int precision) { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision); + return impl::set_value_convert(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision); } PUGI__FN bool xml_attribute::set_value(float rhs) { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision); + return impl::set_value_convert(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision); } PUGI__FN bool xml_attribute::set_value(float rhs, int precision) { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision); + return impl::set_value_convert(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision); } - PUGI__FN bool xml_attribute::set_value(bool rhs) + PUGI__FN bool xml_attribute::set_value(boolean rhs) { if (!_attr) return false; - return impl::set_value_bool(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + return impl::set_value_bool(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); } #ifdef PUGIXML_HAS_LONG_LONG @@ -5456,14 +5572,14 @@ namespace pugi { if (!_attr) return false; - return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); + return impl::set_value_integer(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); } PUGI__FN bool xml_attribute::set_value(unsigned long long rhs) { if (!_attr) return false; - return impl::set_value_integer(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); + return impl::set_value_integer(_attr->value, _attr->value_len, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); } #endif @@ -5526,7 +5642,7 @@ namespace pugi return xml_object_range(begin(), end()); } - PUGI__FN xml_object_range xml_node::children(const char_t* name_) const + PUGI__FN xml_object_range xml_node::children(string_view_t name_) const { return xml_object_range(xml_named_node_iterator(child(name_)._root, _root, name_), xml_named_node_iterator(0, _root, name_)); } @@ -5571,11 +5687,9 @@ namespace pugi return !_root; } - PUGI__FN const char_t* xml_node::name() const + PUGI__FN string_view_t xml_node::name() const { - if (!_root) return PUGIXML_TEXT(""); - const char_t* name = _root->name; - return name ? name : PUGIXML_TEXT(""); + return (_root && _root->name) ? _root->unsafe_name_sv() : PUGIXML_EMPTY_SV; } PUGI__FN xml_node_type xml_node::type() const @@ -5583,51 +5697,39 @@ namespace pugi return _root ? PUGI__NODETYPE(_root) : node_null; } - PUGI__FN const char_t* xml_node::value() const + PUGI__FN string_view_t xml_node::value() const { - if (!_root) return PUGIXML_TEXT(""); - const char_t* value = _root->value; - return value ? value : PUGIXML_TEXT(""); + return (_root && _root->value) ? _root->unsafe_value_sv() : PUGIXML_EMPTY_SV; } - PUGI__FN xml_node xml_node::child(const char_t* name_) const + PUGI__FN xml_node xml_node::child(const string_view_t name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - { - const char_t* iname = i->name; - if (iname && impl::strequal(name_, iname)) - return xml_node(i); - } + if (i->equals_name(name_)) return xml_node(i); return xml_node(); } - PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const + PUGI__FN xml_attribute xml_node::attribute(string_view_t name_) const { if (!_root) return xml_attribute(); - for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) - { - const char_t* iname = i->name; - if (iname && impl::strequal(name_, iname)) + for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) { + if (i->equals_name(name_)) return xml_attribute(i); } return xml_attribute(); } - PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const + PUGI__FN xml_node xml_node::next_sibling(string_view_t name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) - { - const char_t* iname = i->name; - if (iname && impl::strequal(name_, iname)) - return xml_node(i); - } + if (i->equals_name(name_)) return xml_node(i); return xml_node(); } @@ -5637,21 +5739,17 @@ namespace pugi return _root ? xml_node(_root->next_sibling) : xml_node(); } - PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const + PUGI__FN xml_node xml_node::previous_sibling(string_view_t name_) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) - { - const char_t* iname = i->name; - if (iname && impl::strequal(name_, iname)) - return xml_node(i); - } + if (i->equals_name(name_)) return xml_node(i); return xml_node(); } - PUGI__FN xml_attribute xml_node::attribute(const char_t* name_, xml_attribute& hint_) const + PUGI__FN xml_attribute xml_node::attribute(string_view_t name_, xml_attribute& hint_) const { xml_attribute_struct* hint = hint_._attr; @@ -5661,10 +5759,8 @@ namespace pugi if (!_root) return xml_attribute(); // optimistically search from hint up until the end - for (xml_attribute_struct* i = hint; i; i = i->next_attribute) - { - const char_t* iname = i->name; - if (iname && impl::strequal(name_, iname)) + for (xml_attribute_struct* i = hint; i; i = i->next_attribute) { + if (i->equals_name(name_)) { // update hint to maximize efficiency of searching for consecutive attributes hint_._attr = i->next_attribute; @@ -5675,10 +5771,8 @@ namespace pugi // wrap around and search from the first attribute until the hint // 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails - for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute) - { - const char_t* jname = j->name; - if (jname && impl::strequal(name_, jname)) + for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute) { + if (j->equals_name(name_)) { // update hint to maximize efficiency of searching for consecutive attributes hint_._attr = j->next_attribute; @@ -5712,25 +5806,22 @@ namespace pugi return xml_text(_root); } - PUGI__FN const char_t* xml_node::child_value() const + PUGI__FN string_view_t xml_node::child_value() const { - if (!_root) return PUGIXML_TEXT(""); + if (!_root) return PUGIXML_EMPTY_SV; // element nodes can have value if parse_embed_pcdata was used if (PUGI__NODETYPE(_root) == node_element && _root->value) - return _root->value; + return _root->value_sv(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - { - const char_t* ivalue = i->value; - if (impl::is_text_node(i) && ivalue) - return ivalue; - } + if (impl::is_text_node(i) && i->value) + return i->value_sv(); - return PUGIXML_TEXT(""); + return PUGIXML_EMPTY_SV; } - PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const + PUGI__FN string_view_t xml_node::child_value(string_view_t name_) const { return child(name_).child_value(); } @@ -5761,37 +5852,32 @@ namespace pugi return first ? xml_node(first->prev_sibling_c) : xml_node(); } - PUGI__FN bool xml_node::set_name(const char_t* rhs) + PUGI__FN bool xml_node::set_name(string_view_t rhs, boolean shallow_copy) { xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; if (type_ != node_element && type_ != node_pi && type_ != node_declaration) return false; - return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); + return impl::strcpy_insitu(_root->name, _root->name_len, _root->header, impl::xml_memory_page_name_allocated_mask, rhs.data(), rhs.length(), shallow_copy); + } + + PUGI__FN bool xml_node::set_value(string_view_t rhs, boolean shallow_copy) + { + xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; + + if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) + return false; + + return impl::strcpy_insitu(_root->value, _root->value_len, _root->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length(), shallow_copy); } PUGI__FN bool xml_node::set_value(const char_t* rhs, size_t sz) { - xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; - - if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) - return false; - - return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, sz); + return set_value(string_view_t( rhs, sz )); } - PUGI__FN bool xml_node::set_value(const char_t* rhs) - { - xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; - - if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) - return false; - - return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); - } - - PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_) + PUGI__FN xml_attribute xml_node::append_attribute(string_view_t name_, boolean shallow_copy) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); @@ -5803,12 +5889,12 @@ namespace pugi impl::append_attribute(a._attr, _root); - a.set_name(name_); + a.set_name(name_, shallow_copy); return a; } - PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_) + PUGI__FN xml_attribute xml_node::prepend_attribute(string_view_t name_, boolean shallow_copy) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); @@ -5820,12 +5906,12 @@ namespace pugi impl::prepend_attribute(a._attr, _root); - a.set_name(name_); + a.set_name(name_, shallow_copy); return a; } - PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr) + PUGI__FN xml_attribute xml_node::insert_attribute_after(string_view_t name_, const xml_attribute& attr, boolean shallow_copy) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); @@ -5838,12 +5924,12 @@ namespace pugi impl::insert_attribute_after(a._attr, attr._attr, _root); - a.set_name(name_); + a.set_name(name_, shallow_copy); return a; } - PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr) + PUGI__FN xml_attribute xml_node::insert_attribute_before(string_view_t name_, const xml_attribute& attr, boolean shallow_copy) { if (!impl::allow_insert_attribute(type())) return xml_attribute(); if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); @@ -5856,7 +5942,7 @@ namespace pugi impl::insert_attribute_before(a._attr, attr._attr, _root); - a.set_name(name_); + a.set_name(name_, shallow_copy); return a; } @@ -5943,7 +6029,7 @@ namespace pugi impl::append_node(n._root, _root); - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true_value); return n; } @@ -5960,7 +6046,7 @@ namespace pugi impl::prepend_node(n._root, _root); - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true_value); return n; } @@ -5978,7 +6064,7 @@ namespace pugi impl::insert_node_before(n._root, node._root); - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true_value); return n; } @@ -5996,43 +6082,43 @@ namespace pugi impl::insert_node_after(n._root, node._root); - if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); + if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"), true_value); return n; } - PUGI__FN xml_node xml_node::append_child(const char_t* name_) + PUGI__FN xml_node xml_node::append_child(string_view_t name_, boolean shallow_copy) { xml_node result = append_child(node_element); - result.set_name(name_); + result.set_name(name_, shallow_copy); return result; } - PUGI__FN xml_node xml_node::prepend_child(const char_t* name_) + PUGI__FN xml_node xml_node::prepend_child(string_view_t name_, boolean shallow_copy) { xml_node result = prepend_child(node_element); - result.set_name(name_); + result.set_name(name_, shallow_copy); return result; } - PUGI__FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node) + PUGI__FN xml_node xml_node::insert_child_after(string_view_t name_, const xml_node& node, boolean shallow_copy) { xml_node result = insert_child_after(node_element, node); - result.set_name(name_); + result.set_name(name_, shallow_copy); return result; } - PUGI__FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node) + PUGI__FN xml_node xml_node::insert_child_before(string_view_t name_, const xml_node& node, boolean shallow_copy) { xml_node result = insert_child_before(node_element, node); - result.set_name(name_); + result.set_name(name_, shallow_copy); return result; } @@ -6175,7 +6261,7 @@ namespace pugi return moved; } - PUGI__FN bool xml_node::remove_attribute(const char_t* name_) + PUGI__FN bool xml_node::remove_attribute(string_view_t name_) { return remove_attribute(attribute(name_)); } @@ -6215,7 +6301,7 @@ namespace pugi return true; } - PUGI__FN bool xml_node::remove_child(const char_t* name_) + PUGI__FN bool xml_node::remove_child(string_view_t name_) { return remove_child(child(name_)); } @@ -6289,46 +6375,29 @@ namespace pugi return impl::load_buffer_impl(doc, _root, const_cast(contents), size, options, encoding, false, false, &extra->buffer); } - PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const + PUGI__FN xml_node xml_node::find_child_by_attribute(string_view_t name_, string_view_t attr_name, string_view_t attr_value) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - { - const char_t* iname = i->name; - if (iname && impl::strequal(name_, iname)) + if (i->name && i->equals_name(name_)) { for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) - { - const char_t* aname = a->name; - if (aname && impl::strequal(attr_name, aname)) - { - const char_t* avalue = a->value; - if (impl::strequal(attr_value, avalue ? avalue : PUGIXML_TEXT(""))) - return xml_node(i); - } - } + if (a->equals_name(attr_name) && a->equals_value(attr_value)) + return xml_node(i); } - } return xml_node(); } - PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const + PUGI__FN xml_node xml_node::find_child_by_attribute(const string_view_t attr_name, const string_view_t attr_value) const { if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) - { - const char_t* aname = a->name; - if (aname && impl::strequal(attr_name, aname)) - { - const char_t* avalue = a->value; - if (impl::strequal(attr_value, avalue ? avalue : PUGIXML_TEXT(""))) - return xml_node(i); - } - } + if (a->equals_name(attr_name) && a->equals_value(attr_value)) + return xml_node(i); return xml_node(); } @@ -6589,20 +6658,18 @@ namespace pugi return _data() == 0; } - PUGI__FN const char_t* xml_text::get() const + PUGI__FN string_view_t xml_text::get() const { xml_node_struct* d = _data(); - if (!d) return PUGIXML_TEXT(""); - const char_t* value = d->value; - return value ? value : PUGIXML_TEXT(""); + + return (d && d->value) ? d->unsafe_value_sv() : PUGIXML_EMPTY_SV; } - PUGI__FN const char_t* xml_text::as_string(const char_t* def) const + PUGI__FN string_view_t xml_text::as_string(string_view_t def) const { xml_node_struct* d = _data(); - if (!d) return def; - const char_t* value = d->value; - return value ? value : def; + + return (d && d->value) ? d->unsafe_value_sv() : def; } PUGI__FN int xml_text::as_int(int def) const @@ -6663,81 +6730,79 @@ namespace pugi } #endif - PUGI__FN bool xml_text::set(const char_t* rhs, size_t sz) + PUGI__FN bool xml_text::set(string_view_t rhs, boolean shallow_copy) { xml_node_struct* dn = _data_new(); - return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, sz) : false; + return dn ? impl::strcpy_insitu(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs.data(), rhs.length(), shallow_copy) : false; } - PUGI__FN bool xml_text::set(const char_t* rhs) + PUGI__FN bool xml_text::set(const char_t* rhs, size_t sz) { - xml_node_struct* dn = _data_new(); - - return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false; + return set(string_view_t( rhs, sz )); } PUGI__FN bool xml_text::set(int rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; + return dn ? impl::set_value_integer(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI__FN bool xml_text::set(unsigned int rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; + return dn ? impl::set_value_integer(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } PUGI__FN bool xml_text::set(long rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; + return dn ? impl::set_value_integer(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI__FN bool xml_text::set(unsigned long rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; + return dn ? impl::set_value_integer(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } PUGI__FN bool xml_text::set(float rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision) : false; + return dn ? impl::set_value_convert(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision) : false; } PUGI__FN bool xml_text::set(float rhs, int precision) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false; + return dn ? impl::set_value_convert(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false; } PUGI__FN bool xml_text::set(double rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision) : false; + return dn ? impl::set_value_convert(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision) : false; } PUGI__FN bool xml_text::set(double rhs, int precision) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false; + return dn ? impl::set_value_convert(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false; } - PUGI__FN bool xml_text::set(bool rhs) + PUGI__FN bool xml_text::set(boolean rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_bool(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + return dn ? impl::set_value_bool(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; } #ifdef PUGIXML_HAS_LONG_LONG @@ -6745,18 +6810,18 @@ namespace pugi { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; + return dn ? impl::set_value_integer(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; } PUGI__FN bool xml_text::set(unsigned long long rhs) { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_integer(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; + return dn ? impl::set_value_integer(dn->value, dn->value_len, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; } #endif - PUGI__FN xml_text& xml_text::operator=(const char_t* rhs) + PUGI__FN xml_text& xml_text::operator=(string_view_t rhs) { set(rhs); return *this; @@ -6798,7 +6863,7 @@ namespace pugi return *this; } - PUGI__FN xml_text& xml_text::operator=(bool rhs) + PUGI__FN xml_text& xml_text::operator=(boolean rhs) { set(rhs); return *this; @@ -6957,15 +7022,15 @@ namespace pugi return temp; } - PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0) + PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0), _name_len(0) { } - PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _wrap(node), _parent(node.parent()), _name(name) + PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, string_view_t name): _wrap(node), _parent(node.parent()), _name(name.data()), _name_len(static_cast(name.length())) { } - PUGI__FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name): _wrap(ref), _parent(parent), _name(name) + PUGI__FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, string_view_t name): _wrap(ref), _parent(parent), _name(name.data()), _name_len(static_cast(name.length())) { } @@ -6994,7 +7059,7 @@ namespace pugi PUGI__FN xml_named_node_iterator& xml_named_node_iterator::operator++() { assert(_wrap._root); - _wrap = _wrap.next_sibling(_name); + _wrap = _wrap.next_sibling(string_view_t(_name, _name_len)); return *this; } @@ -7007,14 +7072,15 @@ namespace pugi PUGI__FN xml_named_node_iterator& xml_named_node_iterator::operator--() { + string_view_t name = string_view_t(_name, _name_len); if (_wrap._root) - _wrap = _wrap.previous_sibling(_name); + _wrap = _wrap.previous_sibling(name); else { _wrap = _parent.last_child(); - if (!impl::strequal(_wrap.name(), _name)) - _wrap = _wrap.previous_sibling(_name); + if (_wrap.name() != name) + _wrap = _wrap.previous_sibling(name); } return *this; @@ -7448,28 +7514,16 @@ namespace pugi } #ifndef PUGIXML_NO_STL - PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str) + PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const pugi::wstring_view& str) { - assert(str); - - return impl::as_utf8_impl(str, impl::strlength_wide(str)); + return impl::as_utf8_impl(str.data(), str.length()); } - PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string& str) + PUGI__FN std::wstring PUGIXML_FUNCTION as_wide(const pugi::string_view& str) { - return impl::as_utf8_impl(str.c_str(), str.size()); - } + assert(str.data()); - PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const char* str) - { - assert(str); - - return impl::as_wide_impl(str, strlen(str)); - } - - PUGI__FN std::basic_string PUGIXML_FUNCTION as_wide(const std::string& str) - { - return impl::as_wide_impl(str.c_str(), str.size()); + return impl::as_wide_impl(str.data(), str.length()); } #endif @@ -7966,9 +8020,9 @@ PUGI__NS_BEGIN } public: - static xpath_string from_const(const char_t* str) + static xpath_string from_const(string_view_t str) { - return xpath_string(str, false, 0); + return xpath_string(str.data(), false, 0); } static xpath_string from_heap_preallocated(const char_t* begin, const char_t* end) @@ -8139,7 +8193,7 @@ PUGI__NS_BEGIN xpath_string result; // element nodes can have value if parse_embed_pcdata was used - if (n.value()[0]) + if (!n.value().empty()) result.append(xpath_string::from_const(n.value()), alloc); xml_node cur = n.first_child(); @@ -8509,7 +8563,7 @@ PUGI__NS_BEGIN // zero-terminate assert(s < result + result_size); - *s = 0; + *s = '\0'; return xpath_string::from_heap_preallocated(result, s); } @@ -8595,7 +8649,7 @@ PUGI__NS_BEGIN PUGI__FN const char_t* qualified_name(const xpath_node& node) { - return node.attribute() ? node.attribute().name() : node.node().name(); + return node.attribute() ? node.attribute().name().data() : node.node().name().data(); } PUGI__FN const char_t* local_name(const xpath_node& node) @@ -8621,7 +8675,7 @@ PUGI__NS_BEGIN bool operator()(xml_attribute a) const { - const char_t* name = a.name(); + const char_t* name = a.name().data(); if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false; @@ -8631,7 +8685,7 @@ PUGI__NS_BEGIN PUGI__FN const char_t* namespace_uri(xml_node node) { - namespace_uri_predicate pred = node.name(); + namespace_uri_predicate pred = node.name().data(); xml_node p = node; @@ -8639,7 +8693,7 @@ PUGI__NS_BEGIN { xml_attribute a = p.find_attribute(pred); - if (a) return a.value(); + if (a) return a.value().data(); p = p.parent(); } @@ -8649,7 +8703,7 @@ PUGI__NS_BEGIN PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent) { - namespace_uri_predicate pred = attr.name(); + namespace_uri_predicate pred = attr.name().data(); // Default namespace does not apply to attributes if (!pred.prefix) return PUGIXML_TEXT(""); @@ -8660,7 +8714,7 @@ PUGI__NS_BEGIN { xml_attribute a = p.find_attribute(pred); - if (a) return a.value(); + if (a) return a.value().data(); p = p.parent(); } @@ -10543,7 +10597,7 @@ PUGI__NS_BEGIN if (a) { - const char_t* value = a.value(); + const char_t* value = a.value().data(); // strnicmp / strncasecmp is not portable for (const char_t* lit = lang.c_str(); *lit; ++lit) @@ -10565,7 +10619,7 @@ PUGI__NS_BEGIN xml_attribute attr = c.n.node().attribute(_left->_data.nodetest); - return attr && strequal(attr.value(), value) && is_xpath_attribute(attr.name()); + return attr && strequal(attr.value().data(), value) && is_xpath_attribute(attr.name().data()); } case ast_variable: diff --git a/src/pugixml.hpp b/src/pugixml.hpp index bdeb52e..8adbb6f 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -38,6 +38,31 @@ # include #endif +// Tests whether compiler has c++17 support +#if (defined(__cplusplus) && __cplusplus >= 201703L) || \ + (defined(_MSC_VER) && _MSC_VER > 1900 && \ + ((defined(_HAS_CXX17) && _HAS_CXX17 == 1) || \ + (defined(_MSVC_LANG) && (_MSVC_LANG > 201402L)))) +# ifndef PUGI_CXX_STD +# define PUGI_CXX_STD 17 +# endif // C++17 features macro +#endif // C++17 features check + +// Tests whether compiler has c++20 support +#if (defined(__cplusplus) && __cplusplus > 201703L) || \ + (defined(_MSC_VER) && _MSC_VER > 1900 && \ + ((defined(_HAS_CXX20) && _HAS_CXX20 == 1) || \ + (defined(_MSVC_LANG) && (_MSVC_LANG > 201703L)))) +# ifdef PUGI_CXX_STD +# undef PUGI_CXX_STD +# endif +# define PUGI_CXX_STD 20 +#endif // C++20 features check + +#if !defined(PUGI_CXX_STD) +# define PUGI_CXX_STD 11 +#endif + // Macro for deprecated features #ifndef PUGIXML_DEPRECATED # if defined(__GNUC__) @@ -131,6 +156,126 @@ # define PUGIXML_CHAR char #endif + +// The string_view +namespace pugi { +#if PUGI_CXX_STD >= 17 + template > + using basic_string_view = std::basic_string_view; + typedef std::string_view string_view; + typedef std::wstring_view wstring_view; +#else + template > + struct basic_string_view { + const Char* p; + std::size_t s; + + basic_string_view(const std::basic_string& r) + : p(r.c_str()), s(r.size()) { + } + basic_string_view(const Char* ptr) + : p(ptr), s(Traits::length(ptr)) { + } + basic_string_view(const Char* ptr, std::size_t sz) + : p(ptr), s(sz) { + } + + static int compare(const Char* lhs_p, std::size_t lhs_sz, const Char* rhs_p, std::size_t rhs_sz) { + int result = Traits::compare(lhs_p, rhs_p, lhs_sz < rhs_sz ? lhs_sz : rhs_sz); + if (result != 0) + return result; + if (lhs_sz < rhs_sz) + return -1; + if (lhs_sz > rhs_sz) + return 1; + return 0; + } + + const Char* begin() const { + return p; + } + + const Char* end() const { + return p + s; + } + + const Char* cbegin() const { + return p; + } + + const Char* cend() const { + return p + s; + } + + const Char* data() const { + return p; + } + + std::size_t size() const { + return s; + } + + std::size_t length() const { + return size(); + } + + bool empty() const { + return 0 == s; + } + + const Char& operator[](size_t index) const { + return p[index]; + } + + operator std::basic_string() const { + return std::basic_string(data(), size()); + } + + bool operator==(const basic_string_view& r) const { + return compare(p, s, r.data(), r.size()) == 0; + } + + bool operator==(const Char* r) const { + return compare(r, Traits::length(r), p, s) == 0; + } + + bool operator==(const std::basic_string& r) const { + return compare(r.data(), r.size(), p, s) == 0; + } + + bool operator!=(const basic_string_view& r) const { + return !(*this == r); + } + + bool operator!=(const char* r) const { + return !(*this == r); + } + + bool operator!=(const std::basic_string& r) const { + return !(*this == r); + } + }; +} // namespace pugi + +namespace pugi { + typedef basic_string_view string_view; + typedef basic_string_view wstring_view; +#endif +} // namespace pugi + +// The explicit boolean type to avoid compiler ambiguous match const char_t* as scalar type 'bool', +// because we preferred compiler match const char_t* as string_view_t +namespace pugi { + struct boolean { + boolean() : value(false) {} + explicit boolean(bool bval) : value(bval) {} + bool value; + operator bool() const { return value; } + }; + static const boolean (true_value)(true); + static const boolean (false_value)(false); +} // namespace pugi + namespace pugi { // Character type used for all internal storage and operations; depends on PUGIXML_WCHAR_MODE @@ -140,8 +285,13 @@ namespace pugi // String type used for operations that work with STL string; depends on PUGIXML_WCHAR_MODE typedef std::basic_string, std::allocator > string_t; #endif + + // string_view type used for operations that work with pugi::string_view, depends on PUGIXML_WCHAR_MODE + typedef pugi::basic_string_view > string_view_t; } +#define PUGIXML_EMPTY_SV pugi::string_view_t(PUGIXML_TEXT(""), 0) + // The PugiXML namespace namespace pugi { @@ -396,11 +546,12 @@ namespace pugi bool empty() const; // Get attribute name/value, or "" if attribute is empty - const char_t* name() const; - const char_t* value() const; + string_view_t name() const; + + string_view_t value() const; // Get attribute value, or the default value if attribute is empty - const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; + string_view_t as_string(string_view_t def = PUGIXML_EMPTY_SV) const; // Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty int as_int(int def = 0) const; @@ -417,9 +568,9 @@ namespace pugi bool as_bool(bool def = false) const; // Set attribute name/value (returns false if attribute is empty or there is not enough memory) - bool set_name(const char_t* rhs); - bool set_value(const char_t* rhs, size_t sz); - bool set_value(const char_t* rhs); + bool set_name(string_view_t rhs, boolean shallow_copy = pugi::false_value); + bool set_value(string_view_t rhs, boolean shallow_copy = pugi::false_value); + bool set_value(const char_t*, size_t sz); // 1.13 ABI compatible // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set_value(int rhs); @@ -430,7 +581,7 @@ namespace pugi bool set_value(double rhs, int precision); bool set_value(float rhs); bool set_value(float rhs, int precision); - bool set_value(bool rhs); + bool set_value(boolean rhs); #ifdef PUGIXML_HAS_LONG_LONG bool set_value(long long rhs); @@ -438,14 +589,14 @@ namespace pugi #endif // Set attribute value (equivalent to set_value without error checking) - xml_attribute& operator=(const char_t* rhs); + xml_attribute& operator=(string_view_t rhs); xml_attribute& operator=(int rhs); xml_attribute& operator=(unsigned int rhs); xml_attribute& operator=(long rhs); xml_attribute& operator=(unsigned long rhs); xml_attribute& operator=(double rhs); xml_attribute& operator=(float rhs); - xml_attribute& operator=(bool rhs); + xml_attribute& operator=(boolean rhs); #ifdef PUGIXML_HAS_LONG_LONG xml_attribute& operator=(long long rhs); @@ -509,11 +660,11 @@ namespace pugi xml_node_type type() const; // Get node name, or "" if node is empty or it has no name - const char_t* name() const; + string_view_t name() const; // Get node value, or "" if node is empty or it has no value // Note: For text node.value() does not return "text"! Use child_value() or text() methods to access text inside nodes. - const char_t* value() const; + string_view_t value() const; // Get attribute list xml_attribute first_attribute() const; @@ -537,30 +688,30 @@ namespace pugi xml_text text() const; // Get child, attribute or next/previous sibling with the specified name - xml_node child(const char_t* name) const; - xml_attribute attribute(const char_t* name) const; - xml_node next_sibling(const char_t* name) const; - xml_node previous_sibling(const char_t* name) const; + xml_node child(string_view_t name) const; + xml_attribute attribute(string_view_t name) const; + xml_node next_sibling(string_view_t name) const; + xml_node previous_sibling(string_view_t name) const; // Get attribute, starting the search from a hint (and updating hint so that searching for a sequence of attributes is fast) - xml_attribute attribute(const char_t* name, xml_attribute& hint) const; + xml_attribute attribute(string_view_t name, xml_attribute& hint) const; // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA - const char_t* child_value() const; + string_view_t child_value() const; // Get child value of child with specified name. Equivalent to child(name).child_value(). - const char_t* child_value(const char_t* name) const; + string_view_t child_value(string_view_t name) const; // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) - bool set_name(const char_t* rhs); - bool set_value(const char_t* rhs, size_t sz); - bool set_value(const char_t* rhs); + bool set_name(string_view_t rhs, boolean shallow_copy = pugi::false_value); + bool set_value(string_view_t rhs, boolean shallow_copy = pugi::false_value); + bool set_value(const char_t* rhs, size_t sz); // 1.13 ABI compatible // Add attribute with specified name. Returns added attribute, or empty attribute on errors. - xml_attribute append_attribute(const char_t* name); - xml_attribute prepend_attribute(const char_t* name); - xml_attribute insert_attribute_after(const char_t* name, const xml_attribute& attr); - xml_attribute insert_attribute_before(const char_t* name, const xml_attribute& attr); + xml_attribute append_attribute(string_view_t name, boolean shallow_copy = pugi::false_value); + xml_attribute prepend_attribute(string_view_t name, boolean shallow_copy = pugi::false_value); + xml_attribute insert_attribute_after(string_view_t name, const xml_attribute& attr, boolean shallow_copy = pugi::false_value); + xml_attribute insert_attribute_before(string_view_t name, const xml_attribute& attr, boolean shallow_copy = pugi::false_value); // Add a copy of the specified attribute. Returns added attribute, or empty attribute on errors. xml_attribute append_copy(const xml_attribute& proto); @@ -575,10 +726,10 @@ namespace pugi xml_node insert_child_before(xml_node_type type, const xml_node& node); // Add child element with specified name. Returns added node, or empty node on errors. - xml_node append_child(const char_t* name); - xml_node prepend_child(const char_t* name); - xml_node insert_child_after(const char_t* name, const xml_node& node); - xml_node insert_child_before(const char_t* name, const xml_node& node); + xml_node append_child(string_view_t name, boolean shallow_copy = pugi::false_value); + xml_node prepend_child(string_view_t name, boolean shallow_copy = pugi::false_value); + xml_node insert_child_after(string_view_t name, const xml_node& node, boolean shallow_copy = pugi::false_value); + xml_node insert_child_before(string_view_t name, const xml_node& node, boolean shallow_copy = pugi::false_value); // Add a copy of the specified node as a child. Returns added node, or empty node on errors. xml_node append_copy(const xml_node& proto); @@ -594,14 +745,14 @@ namespace pugi // Remove specified attribute bool remove_attribute(const xml_attribute& a); - bool remove_attribute(const char_t* name); + bool remove_attribute(string_view_t name); // Remove all attributes bool remove_attributes(); // Remove specified child bool remove_child(const xml_node& n); - bool remove_child(const char_t* name); + bool remove_child(string_view_t name); // Remove all children bool remove_children(); @@ -660,8 +811,8 @@ namespace pugi } // Find child node by attribute name/value - xml_node find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const; - xml_node find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const; + xml_node find_child_by_attribute(string_view_t name, string_view_t attr_name, string_view_t attr_value) const; + xml_node find_child_by_attribute(string_view_t attr_name, string_view_t attr_value) const; #ifndef PUGIXML_NO_STL // Get the absolute node path from root as a text string. @@ -716,7 +867,7 @@ namespace pugi // Range-based for support for all children with the specified name // Note: name pointer must have a longer lifetime than the returned object; be careful with passing temporaries! - xml_object_range children(const char_t* name) const; + xml_object_range children(string_view_t name) const; // Get node offset in parsed file/string (in char_t units) for debugging purposes ptrdiff_t offset_debug() const; @@ -762,10 +913,10 @@ namespace pugi bool empty() const; // Get text, or "" if object is empty - const char_t* get() const; + string_view_t get() const; // Get text, or the default value if object is empty - const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const; + string_view_t as_string(string_view_t def = PUGIXML_EMPTY_SV) const; // Get text as a number, or the default value if conversion did not succeed or object is empty int as_int(int def = 0) const; @@ -782,8 +933,8 @@ namespace pugi bool as_bool(bool def = false) const; // Set text (returns false if object is empty or there is not enough memory) - bool set(const char_t* rhs, size_t sz); - bool set(const char_t* rhs); + bool set(string_view_t rhs, boolean shallow_copy = pugi::false_value); + bool set(const char_t* rhs, size_t sz); // 1.13 ABI compatible // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") bool set(int rhs); @@ -794,7 +945,7 @@ namespace pugi bool set(double rhs, int precision); bool set(float rhs); bool set(float rhs, int precision); - bool set(bool rhs); + bool set(boolean rhs); #ifdef PUGIXML_HAS_LONG_LONG bool set(long long rhs); @@ -802,14 +953,14 @@ namespace pugi #endif // Set text (equivalent to set without error checking) - xml_text& operator=(const char_t* rhs); + xml_text& operator=(string_view_t rhs); xml_text& operator=(int rhs); xml_text& operator=(unsigned int rhs); xml_text& operator=(long rhs); xml_text& operator=(unsigned long rhs); xml_text& operator=(double rhs); xml_text& operator=(float rhs); - xml_text& operator=(bool rhs); + xml_text& operator=(boolean rhs); #ifdef PUGIXML_HAS_LONG_LONG xml_text& operator=(long long rhs); @@ -931,7 +1082,7 @@ namespace pugi // Construct an iterator which points to the specified node // Note: name pointer is stored in the iterator and must have a longer lifetime than iterator itself - xml_named_node_iterator(const xml_node& node, const char_t* name); + xml_named_node_iterator(const xml_node& node, string_view_t name); // Iterator operators bool operator==(const xml_named_node_iterator& rhs) const; @@ -950,8 +1101,9 @@ namespace pugi mutable xml_node _wrap; xml_node _parent; const char_t* _name; + int _name_len; - xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name); + xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, string_view_t name); }; // Abstract tree walker class (see xml_node::traverse) @@ -1433,12 +1585,10 @@ namespace pugi #ifndef PUGIXML_NO_STL // Convert wide string to UTF8 - std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const wchar_t* str); - std::basic_string, std::allocator > PUGIXML_FUNCTION as_utf8(const std::basic_string, std::allocator >& str); + std::string PUGIXML_FUNCTION as_utf8(const pugi::wstring_view& str); // Convert UTF8 to wide string - std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const char* str); - std::basic_string, std::allocator > PUGIXML_FUNCTION as_wide(const std::basic_string, std::allocator >& str); + std::wstring PUGIXML_FUNCTION as_wide(const pugi::string_view& str); #endif // Memory allocation function interface; returns pointer to allocated memory or NULL on failure diff --git a/tests/main.cpp b/tests/main.cpp index 352b58b..432e334 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -8,6 +8,8 @@ #include +#include + #ifndef PUGIXML_NO_EXCEPTIONS # include #endif @@ -170,6 +172,7 @@ int main(int, char** argv) #ifdef __BORLANDC__ _control87(MCW_EM | PC_53, MCW_EM | MCW_PC); #endif + clock_t start = clock(); // setup temp path as the executable folder std::string temp = argv[0]; @@ -203,9 +206,9 @@ int main(int, char** argv) unsigned int failed = total - passed; if (failed != 0) - printf("FAILURE: %u out of %u tests failed.\n", failed, total); + printf("FAILURE: %u out of %u tests failed, cost %g(s).\n", failed, total, (clock() - start) / static_cast(CLOCKS_PER_SEC)); else - printf("Success: %u tests passed.\n", total); + printf("Success: %u tests passed, cost %g(s).\n", total, (clock() - start) / static_cast(CLOCKS_PER_SEC)); return failed; } diff --git a/tests/test.cpp b/tests/test.cpp index a97116e..2183524 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -42,16 +42,6 @@ static void build_document_order(std::vector& result, pugi::xm } #endif -bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs) -{ - return (!lhs || !rhs) ? lhs == rhs : - #ifdef PUGIXML_WCHAR_MODE - wcscmp(lhs, rhs) == 0; - #else - strcmp(lhs, rhs) == 0; - #endif -} - bool test_node(const pugi::xml_node& node, const pugi::char_t* contents, const pugi::char_t* indent, unsigned int flags) { xml_writer_string writer; diff --git a/tests/test.hpp b/tests/test.hpp index dd14af6..85cac84 100644 --- a/tests/test.hpp +++ b/tests/test.hpp @@ -34,7 +34,10 @@ struct test_runner static const char* _temp_path; }; -bool test_string_equal(const pugi::char_t* lhs, const pugi::char_t* rhs); +inline bool test_string_equal(pugi::string_view_t lhs, const pugi::char_t* rhs) +{ + return lhs == rhs; +} template inline bool test_node_name_value(const Node& node, const pugi::char_t* name, const pugi::char_t* value) { diff --git a/tests/test_document.cpp b/tests/test_document.cpp index 2e2904d..f65d9c2 100644 --- a/tests/test_document.cpp +++ b/tests/test_document.cpp @@ -910,7 +910,7 @@ inline void check_utftest_document(const xml_document& doc) CHECK(static_cast(doc.last_child().last_child().name()[0]) >= 0x80); // check magic string - const char_t* v = doc.last_child().child(STR("Heavy")).previous_sibling().child_value(); + string_view_t v = doc.last_child().child(STR("Heavy")).previous_sibling().child_value(); #ifdef PUGIXML_WCHAR_MODE CHECK(v[0] == 0x4e16 && v[1] == 0x754c && v[2] == 0x6709 && v[3] == 0x5f88 && v[4] == 0x591a && v[5] == wchar_cast(0x8bed) && v[6] == wchar_cast(0x8a00)); @@ -1520,7 +1520,7 @@ TEST(document_load_buffer_utf_truncated) { CHECK(res); - const char_t* name = doc.first_child().name(); + string_view_t name = doc.first_child().name(); #ifdef PUGIXML_WCHAR_MODE CHECK(name[0] == 0x20ac && name[1] == 0); @@ -1565,7 +1565,7 @@ TEST(document_load_stream_truncated) } else { - const char_t* name = doc.first_child().name(); + string_view_t name = doc.first_child().name(); #ifdef PUGIXML_WCHAR_MODE CHECK(name[0] == 0x20ac && name[1] == 0); diff --git a/tests/test_dom_modify.cpp b/tests/test_dom_modify.cpp index 3451f19..082d701 100644 --- a/tests/test_dom_modify.cpp +++ b/tests/test_dom_modify.cpp @@ -30,8 +30,8 @@ TEST_XML(dom_attr_assign, "") node.append_attribute(STR("attr7")) = 0.25f; xml_attribute() = 0.25f; - node.append_attribute(STR("attr8")) = true; - xml_attribute() = true; + node.append_attribute(STR("attr8")) = true_value; + xml_attribute() = true_value; CHECK_NODE(node, STR("")); } @@ -67,8 +67,8 @@ TEST_XML(dom_attr_set_value, "") CHECK(node.append_attribute(STR("attr7")).set_value(0.25f)); CHECK(!xml_attribute().set_value(0.25f)); - CHECK(node.append_attribute(STR("attr8")).set_value(true)); - CHECK(!xml_attribute().set_value(true)); + CHECK(node.append_attribute(STR("attr8")).set_value(true_value)); + CHECK(!xml_attribute().set_value(true_value)); CHECK(node.append_attribute(STR("attr9")).set_value(STR("v2"), 2)); CHECK(!xml_attribute().set_value(STR("v2"))); diff --git a/tests/test_dom_text.cpp b/tests/test_dom_text.cpp index 7d77c09..00ed221 100644 --- a/tests/test_dom_text.cpp +++ b/tests/test_dom_text.cpp @@ -215,7 +215,7 @@ TEST_XML(dom_text_get_no_state, "") xml_text t = node.text(); CHECK(!t); - CHECK(t.get() && *t.get() == 0); + CHECK(t.get().data() && *t.get().data() == 0); CHECK(!node.first_child()); node.append_child(node_pcdata); @@ -310,7 +310,7 @@ TEST_XML(dom_text_assign, "") node.append_child(STR("text7")).text() = 0.25f; xml_text() = 0.25f; - node.append_child(STR("text8")).text() = true; + node.append_child(STR("text8")).text() = true_value; xml_text() = true; CHECK_NODE(node, STR("v1-2147483647-2147483648429496729542949672940.50.25true")); @@ -337,8 +337,8 @@ TEST_XML(dom_text_set_value, "") CHECK(node.append_child(STR("text7")).text().set(0.25f)); CHECK(!xml_text().set(0.25f)); - CHECK(node.append_child(STR("text8")).text().set(true)); - CHECK(!xml_text().set(true)); + CHECK(node.append_child(STR("text8")).text().set(true_value)); + CHECK(!xml_text().set(true_value)); CHECK_NODE(node, STR("v1-2147483647-2147483648429496729542949672940.50.25true")); } diff --git a/tests/test_dom_traverse.cpp b/tests/test_dom_traverse.cpp index 0c1e3af..02117bb 100644 --- a/tests/test_dom_traverse.cpp +++ b/tests/test_dom_traverse.cpp @@ -681,9 +681,9 @@ struct find_predicate_prefix { #ifdef PUGIXML_WCHAR_MODE // can't use wcsncmp here because of a bug in DMC - return std::basic_string(obj.name()).compare(0, wcslen(prefix), prefix) == 0; + return std::basic_string(obj.name().data()).compare(0, wcslen(prefix), prefix) == 0; #else - return strncmp(obj.name(), prefix, strlen(prefix)) == 0; + return strncmp(obj.name().data(), prefix, strlen(prefix)) == 0; #endif } }; diff --git a/tests/test_memory.cpp b/tests/test_memory.cpp index 3258736..0085cf1 100644 --- a/tests/test_memory.cpp +++ b/tests/test_memory.cpp @@ -110,7 +110,7 @@ TEST(memory_large_allocations) // grow for (node = doc.first_child(); node; node = node.next_sibling()) { - std::basic_string s = node.value(); + std::basic_string s(node.value()); CHECK(node.set_value((s + s).c_str())); } diff --git a/tests/test_parse.cpp b/tests/test_parse.cpp index 180c70a..680dae9 100644 --- a/tests/test_parse.cpp +++ b/tests/test_parse.cpp @@ -474,7 +474,7 @@ TEST(parse_pcdata_trim) xml_document doc; CHECK(doc.load_string(td.source, td.flags | parse_trim_pcdata)); - const char_t* value = doc.child(STR("node")) ? doc.child_value(STR("node")) : doc.text().get(); + string_view_t value = doc.child(STR("node")) ? doc.child_value(STR("node")) : doc.text().get(); CHECK_STRING(value, td.result); } } @@ -563,7 +563,7 @@ TEST(parse_escapes_unicode) CHECK(doc.load_string(STR("γγ𤭢"), parse_minimal | parse_escapes)); #ifdef PUGIXML_WCHAR_MODE - const char_t* v = doc.child_value(STR("node")); + string_view_t v = doc.child_value(STR("node")); size_t wcharsize = sizeof(wchar_t); @@ -1100,7 +1100,7 @@ TEST(parse_bom_fragment_invalid_utf8) CHECK(doc.load_buffer("\xef\xbb\xbb", 3, parse_fragment, encoding_utf8)); - const char_t* value = doc.text().get(); + string_view_t value = doc.text().get(); #ifdef PUGIXML_WCHAR_MODE CHECK(value[0] == wchar_cast(0xfefb) && value[1] == 0); @@ -1115,7 +1115,7 @@ TEST(parse_bom_fragment_invalid_utf16) CHECK(doc.load_buffer("\xff\xfe", 2, parse_fragment, encoding_utf16_be)); - const char_t* value = doc.text().get(); + string_view_t value = doc.text().get(); #ifdef PUGIXML_WCHAR_MODE CHECK(value[0] == wchar_cast(0xfffe) && value[1] == 0); @@ -1130,7 +1130,7 @@ TEST(parse_bom_fragment_invalid_utf32) CHECK(doc.load_buffer("\xff\xff\x00\x00", 4, parse_fragment, encoding_utf32_le)); - const char_t* value = doc.text().get(); + string_view_t value = doc.text().get(); #ifdef PUGIXML_WCHAR_MODE CHECK(value[0] == wchar_cast(0xffff) && value[1] == 0); diff --git a/tests/test_unicode.cpp b/tests/test_unicode.cpp index 4cb6114..82bf282 100644 --- a/tests/test_unicode.cpp +++ b/tests/test_unicode.cpp @@ -146,7 +146,7 @@ TEST(as_utf8_invalid) TEST(as_utf8_string) { - std::basic_string s = L"abcd"; + std::wstring s = L"abcd"; CHECK(as_utf8(s) == "abcd"); }