void traverse(const value& tree, const std::function<void (const path&, const value&)>& func, const path& base_path, bool leafs_only ) { if (!leafs_only || tree.empty() || (tree.kind() != kind::array && tree.kind() != kind::object)) func(base_path, tree); if (tree.kind() == kind::object) { for (const auto& field : tree.as_object()) { traverse(field.second, func, base_path + field.first, leafs_only ); } } else if (tree.kind() == kind::array) { for (value::size_type idx = 0; idx < tree.size(); ++idx) traverse(tree[idx], func, base_path + idx, leafs_only ); } }
static void GenStat(Stat& stat, const value& v) { switch (v.kind()) { case kind::array: { for (value::const_array_iterator itr = v.begin_array(); itr != v.end_array(); ++itr) GenStat(stat, *itr); stat.arrayCount++; stat.elementCount += v.size(); } break; case kind::object: { for (value::const_object_iterator itr = v.begin_object(); itr != v.end_object(); ++itr) { GenStat(stat, itr->second); stat.stringLength += itr->first.size(); } stat.objectCount++; stat.memberCount += v.size(); stat.stringCount += v.size(); } break; case kind::string: stat.stringCount++; stat.stringLength += v.size(); break; case kind::integer: case kind::decimal: stat.numberCount++; break; case kind::boolean: if (v.as_boolean()) stat.trueCount++; else stat.falseCount++; break; case kind::null: stat.nullCount++; break; } }
diff_result diff(value left, value right) { diff_result result; if (left == right) { result.same = std::move(left); } else if (left.kind() != right.kind()) { result.left = std::move(left); result.right = std::move(right); } else switch (left.kind()) { case kind::boolean: case kind::decimal: case kind::integer: case kind::null: case kind::string: result.left = std::move(left); result.right = std::move(right); break; case kind::array: result.same = array(); result.left = array(); result.right = array(); for (value::size_type idx = 0; idx < std::min(left.size(), right.size()); ++idx) { diff_result subresult = diff(std::move(left.at(idx)), std::move(right.at(idx))); result.same.push_back(std::move(subresult.same)); result.left.push_back(std::move(subresult.left)); result.right.push_back(std::move(subresult.right)); } if (left.size() > right.size()) result.left.insert(result.left.end_array(), std::make_move_iterator(left.begin_array() + right.size()), std::make_move_iterator(left.end_array()) ); else if (left.size() < right.size()) result.right.insert(result.right.end_array(), std::make_move_iterator(right.begin_array() + left.size()), std::make_move_iterator(right.end_array()) ); break; case kind::object: result.same = object(); result.left = object(); result.right = object(); for (value::object_iterator liter = left.begin_object(); liter != left.end_object(); liter = left.erase(liter) ) { auto riter = right.find(liter->first); if (riter == right.end_object()) { result.left.insert({ liter->first, std::move(liter->second) }); } else if (liter->second == riter->second) { result.same[liter->first] = std::move(liter->second); right.erase(riter); } else { diff_result subresult = diff(std::move(liter->second), std::move(riter->second)); result.left[liter->first] = std::move(subresult.left); result.right[liter->first] = std::move(subresult.right); right.erase(riter); } } for (value::object_iterator riter = right.begin_object(); riter != right.end_object(); riter = right.erase(riter) ) { result.right.insert({ riter->first, std::move(riter->second) }); } break; } return result; }