diff --git a/docs/manual.adoc b/docs/manual.adoc index 5a391ed..25a4db9 100644 --- a/docs/manual.adoc +++ b/docs/manual.adoc @@ -1287,7 +1287,9 @@ bool xml_attribute::set_value(unsigned int rhs); bool xml_attribute::set_value(long rhs); bool xml_attribute::set_value(unsigned long rhs); bool xml_attribute::set_value(double rhs); +bool xml_attribute::set_value(double rhs, int precision); bool xml_attribute::set_value(float rhs); +bool xml_attribute::set_value(float rhs, int precision); bool xml_attribute::set_value(bool rhs); bool xml_attribute::set_value(long long rhs); bool xml_attribute::set_value(unsigned long long rhs); @@ -1439,7 +1441,9 @@ bool xml_text::set(unsigned int rhs); bool xml_text::set(long rhs); bool xml_text::set(unsigned long rhs); bool xml_text::set(double rhs); +bool xml_text::set(double rhs, int precision); bool xml_text::set(float rhs); +bool xml_text::set(float rhs, int precision); bool xml_text::set(bool rhs); bool xml_text::set(long long rhs); bool xml_text::set(unsigned long long rhs); diff --git a/src/pugixml.cpp b/src/pugixml.cpp index af33ef8..20c32c5 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -4665,19 +4665,19 @@ PUGI__NS_BEGIN } template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value) + PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value, int precision) { char buf[128]; - PUGI__SNPRINTF(buf, "%.9g", double(value)); + PUGI__SNPRINTF(buf, "%.*g", precision, double(value)); return set_value_ascii(dest, header, header_mask, buf); } template - PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value) + PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value, int precision) { char buf[128]; - PUGI__SNPRINTF(buf, "%.17g", value); + PUGI__SNPRINTF(buf, "%.*g", precision, value); return set_value_ascii(dest, header, header_mask, buf); } @@ -5342,14 +5342,28 @@ namespace pugi { if (!_attr) return false; - return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); + return impl::set_value_convert(_attr->value, _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); } 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); + return impl::set_value_convert(_attr->value, _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); } PUGI__FN bool xml_attribute::set_value(bool rhs) @@ -6062,7 +6076,7 @@ namespace pugi PUGI__FN bool xml_node::remove_attributes() { if (!_root) return false; - + impl::xml_allocator& alloc = impl::get_allocator(_root); if (!alloc.reserve()) return false; @@ -6545,14 +6559,28 @@ namespace pugi { xml_node_struct* dn = _data_new(); - return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; + return dn ? impl::set_value_convert(dn->value, 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; } 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) : false; + return dn ? impl::set_value_convert(dn->value, 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; } PUGI__FN bool xml_text::set(bool rhs) diff --git a/src/pugixml.hpp b/src/pugixml.hpp index 8986d2a..f658109 100644 --- a/src/pugixml.hpp +++ b/src/pugixml.hpp @@ -263,6 +263,9 @@ namespace pugi // Nodes are indented depending on their depth in DOM tree, a default declaration is output if document has none. const unsigned int format_default = format_indent; + const int default_double_precision = 17; + const int default_float_precision = 9; + // Forward declarations struct xml_attribute_struct; struct xml_node_struct; @@ -410,7 +413,9 @@ namespace pugi bool set_value(long rhs); bool set_value(unsigned long rhs); bool set_value(double rhs); + bool set_value(double rhs, int precision); bool set_value(float rhs); + bool set_value(float rhs, int precision); bool set_value(bool rhs); #ifdef PUGIXML_HAS_LONG_LONG @@ -767,7 +772,9 @@ namespace pugi bool set(long rhs); bool set(unsigned long rhs); bool set(double rhs); + bool set(double rhs, int precision); bool set(float rhs); + bool set(float rhs, int precision); bool set(bool rhs); #ifdef PUGIXML_HAS_LONG_LONG diff --git a/tests/test_dom_modify.cpp b/tests/test_dom_modify.cpp index 319555a..ff9d440 100644 --- a/tests/test_dom_modify.cpp +++ b/tests/test_dom_modify.cpp @@ -1762,6 +1762,31 @@ TEST(dom_fp_roundtrip_min_max_double) CHECK(fp_equal(node.text().as_double(), std::numeric_limits::max())); } +TEST(dom_fp_double_custom_precision) +{ + xml_document doc; + xml_node node = doc.append_child(STR("node")); + xml_attribute attr = node.append_attribute(STR("attr")); + + attr.set_value(std::numeric_limits::min(), 20); + CHECK(fp_equal(attr.as_double(), std::numeric_limits::min())); + + attr.set_value(1.0f, 5); + CHECK(fp_equal(attr.as_double(), static_cast(1.0f))); + + attr.set_value(3.1415926f, 3); + CHECK(!fp_equal(attr.as_double(), static_cast(3.1415926f))); + + node.text().set(1.0f, 5); + CHECK(fp_equal(node.text().as_double(), static_cast(1.0f))); + + node.text().set(3.1415926f, 3); + CHECK(!fp_equal(node.text().as_double(), static_cast(3.1415926f))); + + node.text().set(std::numeric_limits::max(), 20); + CHECK(fp_equal(node.text().as_double(), std::numeric_limits::max())); +} + const double fp_roundtrip_base[] = { 0.31830988618379067154,