diff --git a/include/jsonxx.h b/include/jsonxx.h index f70e369..37c8b5a 100644 --- a/include/jsonxx.h +++ b/include/jsonxx.h @@ -5,15 +5,16 @@ // Sean Middleditch // rlyeh -#pragma once +#ifndef JSONXX_DEFINE_H +#define JSONXX_DEFINE_H #include -#include #include +#include #include #include #include -#include +#include // jsonxx versioning: major.minor-extra where // major = { number } @@ -33,28 +34,32 @@ # define JSONXX_COMPILER_HAS_CXX11 0 #endif -#ifdef _MSC_VER -// disable the C4127 warning if using VC, see https://stackoverflow.com/a/12042515 -# define JSONXX_ASSERT(...) \ - do \ - { \ - __pragma(warning(push)) __pragma(warning(disable : 4127)) if (jsonxx::Assertions) __pragma(warning(pop)) \ - jsonxx::assertion(__FILE__, __LINE__, #__VA_ARGS__, bool(__VA_ARGS__)); \ - __pragma(warning(push)) __pragma(warning(disable : 4127)) \ - } while (0) __pragma(warning(pop)) +#define JSONXX_ASSERT(...) \ + do \ + { \ + if (jsonxx::Assertions) \ + jsonxx::assertion(__FILE__, __LINE__, #__VA_ARGS__, bool(__VA_ARGS__)); \ + } while (0) + +#ifndef JSONXX_HANDLE_INFINITY +# define JSONXX_HANDLE_INFINITY 1 +#endif + +#ifdef DEBUG +# define JSONXX_WARN(...) std::cerr << "[WARN] " << __VA_ARGS__ << std::endl; #else -# define JSONXX_ASSERT(...) \ - do \ - { \ - if (jsonxx::Assertions) \ - jsonxx::assertion(__FILE__, __LINE__, #__VA_ARGS__, bool(__VA_ARGS__)); \ - } while (0) +# define JSONXX_WARN(...) ; #endif namespace jsonxx { -// FIXME(hjiang): Those should really be dynamic. +enum PrintMode +{ + Pretty, + Compact, +}; + // Settings enum Settings { @@ -66,37 +71,18 @@ enum Settings // values Parser = Permissive, // permissive or strict parsing UnquotedKeys = Disabled, // support of unquoted keys - Assertions = Enabled // enabled or disabled assertions (these asserts work both in DEBUG and RELEASE builds) -}; - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable : 4127) -#endif -inline bool -parser_is_strict() -{ - return Parser == Strict; -} -inline bool -parser_is_permissive() -{ - return Parser == Permissive; -} -inline bool -unquoted_keys_are_enabled() -{ - return UnquotedKeys == Enabled; -} -#ifdef _MSC_VER -# pragma warning(pop) +#if DEBUG + Assertions = Enabled // enabled or disabled assertions (these asserts work both in DEBUG and RELEASE builds) +#else + Assertions = Disabled // enabled or disabled assertions (these asserts work both in DEBUG and RELEASE builds) #endif +}; // Constants for .write() and .xml() methods enum Format { JSON = 0, // JSON output - JSONx = 1, // XML output, JSONx format. see https://goo.gl/I3cxs + JSONx = 1, // XML output, JSONx format. see http://goo.gl/I3cxs JXML = 2, // XML output, JXML format. see https://github.com/r-lyeh/JXML JXMLex = 3, // XML output, JXMLex format. see https://github.com/r-lyeh/JXMLex TaggedXML = 4 // XML output, tagged XML format. see https://github.com/hjiang/jsonxx/issues/12 @@ -112,6 +98,21 @@ class Value; class Object; class Array; +// Range of Number. Valid numbers outside the range as considered infinite +constexpr Number MaxNumberRange = std::numeric_limits::max(); +constexpr Number MinNumberRange = -std::numeric_limits::max(); + +// JSON representation of infinite numbers +constexpr const char * InfinityRepresentation = "1e500"; + +// Default value +static const String EmptyString = ""; +static const Number Zero = 0; +static const Number MinusOne = -1; +static const Number One = 1; +static const Boolean True = true; +static const Boolean False = false; + // Identity meta-function template struct identity @@ -161,6 +162,11 @@ class Object const T & get(const std::string & key, const typename identity::type & default_value) const; + // Delete unsafe operation + template + const T & + get(const std::string & key, typename identity::type && default_value) const = delete; + size_t size() const; bool @@ -169,11 +175,12 @@ class Object const std::map & kv_map() const; std::string - json() const; + json(PrintMode printMode = PrintMode::Compact, int floatPrecision = std::numeric_limits::digits10 + 1) const; std::string xml(unsigned format = JSONx, const std::string & header = std::string(), - const std::string & attrib = std::string()) const; + const std::string & attrib = std::string(), + int floatPrecision = std::numeric_limits::digits10 + 1) const; std::string write(unsigned format) const; @@ -212,6 +219,8 @@ class Object std::string odd; }; +static const Object EmptyObject = {}; + class Array { public: @@ -238,17 +247,23 @@ class Array const T & get(unsigned int i, const typename identity::type & default_value) const; + // Delete unsafe operation + template + const T & + get(unsigned int i, typename identity::type && default_value) const = delete; + const std::vector & values() const { return values_; } std::string - json() const; + json(PrintMode printMode = PrintMode::Compact, int floatPrecision = std::numeric_limits::digits10 + 1) const; std::string xml(unsigned format = JSONx, const std::string & header = std::string(), - const std::string & attrib = std::string()) const; + const std::string & attrib = std::string(), + int floatPrecision = std::numeric_limits::digits10 + 1) const; std::string write(unsigned format) const @@ -263,13 +278,6 @@ class Array parse(const std::string & input); typedef std::vector container; void - append(const Array & other); - void - append(const Value & value) - { - import(value); - } - void import(const Array & other); void import(const Value & value); @@ -290,6 +298,8 @@ class Array container values_; }; +static const Array EmptyArray = {}; + // A value could be a number, an array, a string, an object, a // boolean, or null class Value @@ -300,15 +310,22 @@ class Value void reset(); +#ifdef JSONXX_ALLOW_INVALID_TYPES template + [[deprecated("this type is not natively supported by jsonxx, therefore its value will be converted to 'null'")]] void - import(const T &) + import(const T & t) { reset(); type_ = INVALID_; - // debug - // std::cout << "[WARN] No support for " << typeid(t).name() << std::endl; + JSONXX_WARN("No JSONXX support for " << typeid(t).name()); } +#else + template + void + import(const T & t) = delete; +#endif + void import(const bool & b) { @@ -316,19 +333,18 @@ class Value type_ = BOOL_; bool_value_ = b; } -#define local_number(TYPE) \ +#define $number(TYPE) \ void import(const TYPE & n) \ { \ reset(); \ type_ = NUMBER_; \ number_value_ = static_cast(n); \ } - local_number(char) local_number(int) local_number(long) local_number(long long) local_number(unsigned char) - local_number(unsigned int) local_number(unsigned long) local_number(unsigned long long) local_number(float) - local_number(double) local_number(long double) -#undef local_number + $number(char) $number(int) $number(long) $number(long long) $number(unsigned char) $number(unsigned int) + $number(unsigned long) $number(unsigned long long) $number(float) $number(double) $number(long double) +#undef $number #if JSONXX_COMPILER_HAS_CXX11 > 0 - void import(const std::nullptr_t &) + void import(const std::nullptr_t &) { reset(); type_ = NULL_; @@ -348,6 +364,24 @@ class Value *(string_value_ = new String()) = s; } void + import(const std::string_view & sv) + { + reset(); + type_ = STRING_; + *(string_value_ = new String()) = sv; + } + template + void + import(const std::vector & array) + { + Array a; + for (const auto & elmt : array) + { + a << elmt; + } + import(a); + } + void import(const Array & a) { reset(); @@ -408,14 +442,31 @@ class Value return *this; } Value(const Value & other); - template - Value(const T & t) - : type_(INVALID_) - { - import(t); + +#define $Value(TYPE) \ + Value(const TYPE & t) \ + : type_(INVALID_) \ + { \ + import(t); \ } - template - Value(const char (&t)[N]) + +#ifdef JSONXX_ALLOW_INVALID_TYPES + template + $Value(T) +#else + $Value(bool) $Value(char) $Value(int) $Value(long) $Value(long long) $Value(unsigned char) $Value(unsigned int) + $Value(unsigned long) $Value(unsigned long long) $Value(float) $Value(double) $Value(long double) +# if JSONXX_COMPILER_HAS_CXX11 > 0 + $Value(std::nullptr_t) +# endif + $Value(Null) $Value(String) $Value(std::string_view) template + $Value(std::vector) $Value(Array) $Value(Object) +#endif + +#undef $Value + + template + Value(const char (&t)[N]) : type_(INVALID_) { import(std::string(t)); @@ -464,6 +515,8 @@ class Value parse(std::istream & input, Value & value); }; +static const Value EmptyValue = {}; + template bool Array::has(unsigned int i) const @@ -501,15 +554,15 @@ template const T & Array::get(unsigned int i, const typename identity::type & default_value) const { - if (has(i)) + if (i < size()) { const Value * v = values_.at(i); - return v->get(); - } - else - { - return default_value; + if (v->is()) + { + return v->get(); + } } + return default_value; } template @@ -540,9 +593,10 @@ template const T & Object::get(const std::string & key, const typename identity::type & default_value) const { - if (has(key)) + auto iterator = value_map_.find(key); + if (iterator != value_map_.end() && iterator->second->is()) { - return value_map_.find(key)->second->get(); + return iterator->second->get(); } else { @@ -700,7 +754,6 @@ Object::operator<<(const T & value) *this << Value(value); return *this; } - } // namespace jsonxx std::ostream & @@ -709,3 +762,5 @@ std::ostream & operator<<(std::ostream & stream, const jsonxx::Object & v); std::ostream & operator<<(std::ostream & stream, const jsonxx::Array & v); + +#endif diff --git a/src/jsonxx.cc b/src/jsonxx.cc index f259e95..6ff8564 100644 --- a/src/jsonxx.cc +++ b/src/jsonxx.cc @@ -8,12 +8,14 @@ #include "jsonxx.h" #include +#include #include #include #include #include #include #include +#include // Snippet that creates an assertion function that works both in DEBUG & RELEASE mode. // JSONXX_ASSERT(...) macro will redirect to this. assert() macro is kept untouched. @@ -58,6 +60,8 @@ parse_null(std::istream & input); bool parse_number(std::istream & input, Number & value); bool +parse_number_inf(std::istream & input, Number & value, std::streampos rollback); +bool parse_object(std::istream & input, Object & object); bool parse_string(std::istream & input, String & value); @@ -103,7 +107,7 @@ parse_string(std::istream & input, String & value) char ch = '\0', delimiter = '"'; if (!match("\"", input)) { - if (parser_is_strict()) + if (Parser == Strict) { return false; } @@ -155,7 +159,7 @@ parse_string(std::istream & input, String & value) ss << std::hex << ch; } if (input.good() && (ss >> i)) - value.push_back(static_cast(i)); + value.push_back(i); } break; default: @@ -237,13 +241,75 @@ parse_number(std::istream & input, Number & value) input >> value; if (input.fail()) { + if (parse_number_inf(input, value, rollback)) + { + return true; + } + input.clear(); input.seekg(rollback); return false; } + +#if JSONXX_HANDLE_INFINITY + if (value >= MaxNumberRange) + { + value = std::numeric_limits::infinity(); + } + else if (value <= MinNumberRange) + { + value = -std::numeric_limits::infinity(); + } +#endif return true; } +bool +parse_number_inf(std::istream & input, Number & value, std::streampos rollback) +{ + input.clear(); + input.seekg(rollback); + + switch (input.peek()) + { + case '-': + input.get(); + value = -std::numeric_limits::infinity(); + break; + case '+': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + input.get(); + value = std::numeric_limits::infinity(); + break; + default: + return false; + } + + int ch; + do + { + ch = input.get(); + } while (isdigit(ch)); + + if (ch != 'E' && ch != 'e') + { + return false; + } + + int exponent; + input >> exponent; + return !input.fail(); +} + bool parse_bool(std::istream & input, Boolean & value) { @@ -267,7 +333,7 @@ parse_null(std::istream & input) { return true; } - if (parser_is_strict()) + if (Parser == Strict) { return false; } @@ -289,7 +355,7 @@ parse_object(std::istream & input, Object & object) bool parse_comment(std::istream & input) { - if (parser_is_permissive()) + if (Parser == Permissive) if (!input.eof() && input.peek() == '/') { char ch0(0); @@ -334,10 +400,7 @@ Object::Object() : value_map_() {} -Object::~Object() -{ - reset(); -} +Object::~Object() { reset(); } bool Object::parse(std::istream & input, Object & object) @@ -356,11 +419,11 @@ Object::parse(std::istream & input, Object & object) do { std::string key; - if (unquoted_keys_are_enabled()) + if (UnquotedKeys == Enabled) { if (!parse_identifier(input, key)) { - if (parser_is_permissive()) + if (Parser == Permissive) { if (input.peek() == '}') break; @@ -372,7 +435,7 @@ Object::parse(std::istream & input, Object & object) { if (!parse_string(input, key)) { - if (parser_is_permissive()) + if (Parser == Permissive) { if (input.peek() == '}') break; @@ -390,24 +453,7 @@ Object::parse(std::istream & input, Object & object) delete v; break; } - // TODO(hjiang): Add an option to allow duplicated keys? - if (object.value_map_.find(key) == object.value_map_.end()) - { - object.value_map_[key] = v; - } - else - { - if (parser_is_permissive()) - { - delete object.value_map_[key]; - object.value_map_[key] = v; - } - else - { - delete v; - return false; - } - } + object.value_map_[key] = v; } while (match(",", input)); @@ -481,7 +527,6 @@ Value::parse(std::istream & input, Value & value) return true; } delete value.array_value_; - value.array_value_ = 0; } value.object_value_ = new Object(); if (parse_object(input, *value.object_value_)) @@ -490,7 +535,6 @@ Value::parse(std::istream & input, Value & value) return true; } delete value.object_value_; - value.object_value_ = 0; return false; } @@ -498,10 +542,7 @@ Array::Array() : values_() {} -Array::~Array() -{ - reset(); -} +Array::~Array() { reset(); } bool Array::parse(std::istream & input, Array & array) @@ -671,43 +712,32 @@ typedef unsigned char byte; std::string escape_string(const std::string & input, const bool quote = false) { - static std::string map[256], *once = 0; - static std::mutex mutex; - if (!once) - { - // The problem here is that, once is initializing at the end of job, but if multithreaded application is starting - // this for the first time it will jump into this part with several threads and cause double free or corruptions. To - // prevent it, it is required to have mutex, to lock other threads while only one of them is constructing the static - // map. - mutex.lock(); - if (!once) + static std::string map[256]; + static std::once_flag once; + std::call_once(once, [] { + // base + for (int i = 0; i < 256; ++i) { - // base - for (int i = 0; i < 256; ++i) - { - map[i] = std::string() + char(i); - } - // non-printable - for (int i = 0; i < 32; ++i) - { - std::stringstream str; - str << "\\u" << std::hex << std::setw(4) << std::setfill('0') << i; - map[i] = str.str(); - } - // exceptions - map[byte('"')] = "\\\""; - map[byte('\\')] = "\\\\"; - map[byte('/')] = "\\/"; - map[byte('\b')] = "\\b"; - map[byte('\f')] = "\\f"; - map[byte('\n')] = "\\n"; - map[byte('\r')] = "\\r"; - map[byte('\t')] = "\\t"; - - once = map; + map[i] = std::string() + char(i); } - mutex.unlock(); - } + // non-printable + for (int i = 0; i < 32; ++i) + { + std::stringstream str; + str << "\\u" << std::hex << std::setw(4) << std::setfill('0') << i; + map[i] = str.str(); + } + // exceptions + map[byte('"')] = "\\\""; + map[byte('\\')] = "\\\\"; + map[byte('/')] = "\\/"; + map[byte('\b')] = "\\b"; + map[byte('\f')] = "\\f"; + map[byte('\n')] = "\\n"; + map[byte('\r')] = "\\r"; + map[byte('\t')] = "\\t"; + }); + std::string output; output.reserve(input.size() * 2 + 2); // worst scenario if (quote) @@ -729,19 +759,41 @@ remove_last_comma(const std::string & _input) std::string input(_input); size_t size = input.size(); if (size > 2) + { if (input[size - 2] == ',') input[size - 2] = ' '; + if (input[size - 1] == ',') // compact case + input.resize(size - 1); + } return input; } std::string -tag(unsigned format, unsigned depth, const std::string & name, const jsonxx::Value & t) +tag(unsigned format, + unsigned depth, + const std::string & name, + const jsonxx::Value & t, + PrintMode printMode, + int floatPrecision = std::numeric_limits::digits10 + 1) { std::stringstream ss; - const std::string tab(depth, '\t'); + std::string tab(depth, '\t'); + std::string newLine("\n"); + std::string space(" "); + + switch (printMode) + { + case Compact: + tab = ""; + newLine = ""; + space = ""; + break; + case Pretty: + break; + } if (!name.empty()) - ss << tab << '\"' << escape_string(name) << '\"' << ':' << ' '; + ss << tab << '\"' << escape_string(name) << '\"' << ':' << space; else ss << tab; @@ -750,42 +802,62 @@ tag(unsigned format, unsigned depth, const std::string & name, const jsonxx::Val default: case jsonxx::Value::NULL_: ss << "null"; - return ss.str() + ",\n"; + return ss.str() + "," + newLine; case jsonxx::Value::BOOL_: ss << (t.bool_value_ ? "true" : "false"); - return ss.str() + ",\n"; + return ss.str() + "," + newLine; case jsonxx::Value::ARRAY_: - ss << "[\n"; + ss << "[" + newLine; for (Array::container::const_iterator it = t.array_value_->values().begin(), end = t.array_value_->values().end(); it != end; ++it) - ss << tag(format, depth + 1, std::string(), **it); + ss << tag(format, depth + 1, std::string(), **it, printMode, floatPrecision); return remove_last_comma(ss.str()) + tab + "]" - ",\n"; + "," + + newLine; case jsonxx::Value::STRING_: ss << '\"' << escape_string(*t.string_value_) << '\"'; - return ss.str() + ",\n"; + return ss.str() + "," + newLine; case jsonxx::Value::OBJECT_: - ss << "{\n"; + ss << "{" + newLine; for (Object::container::const_iterator it = t.object_value_->kv_map().begin(), end = t.object_value_->kv_map().end(); it != end; ++it) - ss << tag(format, depth + 1, it->first, *it->second); + ss << tag(format, depth + 1, it->first, *it->second, printMode, floatPrecision); return remove_last_comma(ss.str()) + tab + "}" - ",\n"; + "," + + newLine; case jsonxx::Value::NUMBER_: - // max precision - ss << std::setprecision(std::numeric_limits::digits10 + 1); - ss << t.number_value_; - return ss.str() + ",\n"; + if (isfinite(t.number_value_)) + { + // max precision + ss << std::setprecision(floatPrecision); + ss << t.number_value_; + } +#if JSONXX_HANDLE_INFINITY + else if (t.number_value_ > MaxNumberRange) + { + ss << InfinityRepresentation; + } + else if (t.number_value_ < MinNumberRange) + { + ss << '-' << InfinityRepresentation; + } +#endif + else + { + JSONXX_WARN("No JSONXX support for number value " << t.number_value_); + ss << "null"; // NaN or other stuff we cannot represent + } + return ss.str() + "," + newLine; } } } // namespace json @@ -796,9 +868,9 @@ namespace xml std::string escape_attrib(const std::string & input) { - static std::string map[256], *once = 0; - if (!once) - { + static std::string map[256]; + static std::once_flag once; + std::call_once(once, [] { for (int i = 0; i < 256; ++i) map[i] = "_"; for (int i = int('a'); i <= int('z'); ++i) @@ -807,8 +879,8 @@ escape_attrib(const std::string & input) map[i] = std::string() + char(i); for (int i = int('0'); i <= int('9'); ++i) map[i] = std::string() + char(i); - once = map; - } + }); + std::string output; output.reserve(input.size()); // worst scenario for (std::string::const_iterator it = input.begin(), end = input.end(); it != end; ++it) @@ -819,9 +891,9 @@ escape_attrib(const std::string & input) std::string escape_tag(const std::string & input, unsigned format) { - static std::string map[256], *once = 0; - if (!once) - { + static std::string map[256]; + static std::once_flag once; + std::call_once(once, [=] { for (int i = 0; i < 256; ++i) map[i] = std::string() + char(i); map[byte('<')] = "<"; @@ -839,9 +911,8 @@ escape_tag(const std::string & input, unsigned format) map[byte('&')] = "&"; break; } + }); - once = map; - } std::string output; output.reserve(input.size() * 5); // worst scenario for (std::string::const_iterator it = input.begin(), end = input.end(); it != end; ++it) @@ -985,7 +1056,8 @@ tag(unsigned format, unsigned depth, const std::string & name, const jsonxx::Value & t, - const std::string & attr = std::string()) + const std::string & attr = std::string(), + int floatPrecision = std::numeric_limits::digits10 + 1) { std::stringstream ss; const std::string tab(depth, '\t'); @@ -1005,7 +1077,7 @@ tag(unsigned format, for (Array::container::const_iterator it = t.array_value_->values().begin(), end = t.array_value_->values().end(); it != end; ++it) - ss << tag(format, depth + 1, std::string(), **it); + ss << tag(format, depth + 1, std::string(), **it, std::string(), floatPrecision); return tab + open_tag(format, 'a', name, attr) + '\n' + ss.str() + tab + close_tag(format, 'a', name) + '\n'; case jsonxx::Value::STRING_: @@ -1018,12 +1090,12 @@ tag(unsigned format, end = t.object_value_->kv_map().end(); it != end; ++it) - ss << tag(format, depth + 1, it->first, *it->second); + ss << tag(format, depth + 1, it->first, *it->second, std::string(), floatPrecision); return tab + open_tag(format, 'o', name, attr) + '\n' + ss.str() + tab + close_tag(format, 'o', name) + '\n'; case jsonxx::Value::NUMBER_: // max precision - ss << std::setprecision(std::numeric_limits::digits10 + 1); + ss << std::setprecision(floatPrecision); ss << t.number_value_; return tab + open_tag(format, 'n', name, std::string(), format == jsonxx::JXMLex ? ss.str() : std::string()) + ss.str() + close_tag(format, 'n', name) + '\n'; @@ -1045,8 +1117,8 @@ const char * defheader[] = { "", const char * defrootattrib[] = { "", " xsi:schemaLocation=\"http://www.datapower.com/schemas/json jsonx.xsd\"" - " xmlns:xsi=\"https://www.w3.org/2001/XMLSchema-instance\"" - " xmlns:json=\"https://www.ibm.com/xmlns/prod/2009/jsonx\"", + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"" + " xmlns:json=\"http://www.ibm.com/xmlns/prod/2009/jsonx\"", "", @@ -1059,7 +1131,7 @@ const char * defrootattrib[] = { "", } // namespace std::string -Object::json() const +Object::json(PrintMode printMode, int floatPrecision) const { using namespace json; @@ -1067,14 +1139,14 @@ Object::json() const v.object_value_ = const_cast(this); v.type_ = jsonxx::Value::OBJECT_; - std::string result = tag(jsonxx::JSON, 0, std::string(), v); + std::string result = tag(jsonxx::JSON, 0, std::string(), v, printMode, floatPrecision); v.object_value_ = 0; return remove_last_comma(result); } std::string -Object::xml(unsigned format, const std::string & header, const std::string & attrib) const +Object::xml(unsigned format, const std::string & header, const std::string & attrib, int floatPrecision) const { using namespace xml; JSONXX_ASSERT(format == jsonxx::JSONx || format == jsonxx::JXML || format == jsonxx::JXMLex || @@ -1084,14 +1156,15 @@ Object::xml(unsigned format, const std::string & header, const std::string & att v.object_value_ = const_cast(this); v.type_ = jsonxx::Value::OBJECT_; - std::string result = tag(format, 0, std::string(), v, attrib.empty() ? std::string(defrootattrib[format]) : attrib); + std::string result = + tag(format, 0, std::string(), v, attrib.empty() ? std::string(defrootattrib[format]) : attrib, floatPrecision); v.object_value_ = 0; return (header.empty() ? std::string(defheader[format]) : header) + result; } std::string -Array::json() const +Array::json(PrintMode printMode, int floatPrecision) const { using namespace json; @@ -1099,14 +1172,14 @@ Array::json() const v.array_value_ = const_cast(this); v.type_ = jsonxx::Value::ARRAY_; - std::string result = tag(jsonxx::JSON, 0, std::string(), v); + std::string result = tag(jsonxx::JSON, 0, std::string(), v, printMode, floatPrecision); v.array_value_ = 0; return remove_last_comma(result); } std::string -Array::xml(unsigned format, const std::string & header, const std::string & attrib) const +Array::xml(unsigned format, const std::string & header, const std::string & attrib, int floatPrecision) const { using namespace xml; JSONXX_ASSERT(format == jsonxx::JSONx || format == jsonxx::JXML || format == jsonxx::JXMLex || @@ -1116,7 +1189,8 @@ Array::xml(unsigned format, const std::string & header, const std::string & attr v.array_value_ = const_cast(this); v.type_ = jsonxx::Value::ARRAY_; - std::string result = tag(format, 0, std::string(), v, attrib.empty() ? std::string(defrootattrib[format]) : attrib); + std::string result = + tag(format, 0, std::string(), v, attrib.empty() ? std::string(defrootattrib[format]) : attrib, floatPrecision); v.array_value_ = 0; return (header.empty() ? std::string(defheader[format]) : header) + result; @@ -1225,14 +1299,8 @@ xml(const std::string & input, unsigned format) } -Object::Object(const Object & other) -{ - import(other); -} -Object::Object(const std::string & key, const Value & value) -{ - import(key, value); -} +Object::Object(const Object & other) { import(other); } +Object::Object(const std::string & key, const Value & value) { import(key, value); } void Object::import(const Object & other) { @@ -1343,26 +1411,8 @@ Object::parse(const std::string & input) } -Array::Array(const Array & other) -{ - import(other); -} -Array::Array(const Value & value) -{ - import(value); -} -void -Array::append(const Array & other) -{ - if (this != &other) - { - values_.push_back(new Value(other)); - } - else - { - append(Array(*this)); - } -} +Array::Array(const Array & other) { import(other); } +Array::Array(const Value & value) { import(value); } void Array::import(const Array & other) {