Skip to content

Commit

Permalink
support THROW_UNKNOWN_KEY
Browse files Browse the repository at this point in the history
  • Loading branch information
bbbgan committed Jul 10, 2023
1 parent a0642bb commit 21f4578
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 9 deletions.
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ set(TEST_YAML test/test_yaml.cpp test/test_yaml_bech.cpp)
set(YAMLBENCH benchmark/yaml_benchmark.cpp)
set(TEST_NOTHROW test/test_yaml_nothrow.cpp)
set(TEST_UTIL test/test_util.cpp)
set(TEST_XMLNOTHROW test/test_xml_nothrow.cpp)

add_executable(json_example ${JSON_EXAMPLE})
add_executable(xml_example ${XML_EXAMPLE})
Expand All @@ -67,6 +68,7 @@ add_executable(test_yaml ${TEST_YAML})
add_executable(yaml_benchmark ${YAMLBENCH})
add_executable(test_nothrow ${TEST_NOTHROW})
add_executable(test_util ${TEST_UTIL})
add_executable(test_xml_nothrow ${TEST_XMLNOTHROW})

# unit test
option(BUILD_UNIT_TESTS "Build unit tests" ON)
Expand All @@ -91,3 +93,4 @@ add_test(NAME test_xml COMMAND test_xml)
add_test(NAME test_yaml COMMAND test_yaml)
add_test(NAME test_nothrow COMMAND test_nothrow)
add_test(NAME test_util COMMAND test_util)
add_test(NAME test_xml_nothrow COMMAND test_xml_nothrow)
8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,10 @@ person p = {"admin", 20};
iguana::string_stream ss; // here use std::string is also ok
iguana::to_xml(ss, p);
std::cout << ss.str() << std::endl;
// you can also call iguana::to_xml_pretty to get pretty string
iguana::string_stream s;
iguana::to_xml_pretty(s, p);
std::cout << s.str() << std::endl;

// deserialization the structure from the string
std::string xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"> <name>buke</name> <age>30</name>";
iguana::from_xml(p, xml.data());
iguana::from_xml(p, xml);
```
#### Serialization of yaml
Expand Down Expand Up @@ -212,7 +208,7 @@ std::string str = R"(
</library>
)";
library_t lib;
iguana::from_xml(lib, str.data());
iguana::from_xml(lib, str);
```
#### yaml

Expand Down
4 changes: 2 additions & 2 deletions iguana/json_writer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,12 +174,12 @@ template <typename Stream, tuple_t T>
IGUANA_INLINE void render_json_value(Stream &s, T &&t) {
using U = typename std::decay_t<T>;
s.push_back('[');
const size_t size = std::tuple_size_v<U>;
constexpr size_t size = std::tuple_size_v<U>;
for_each(std::forward<T>(t),
[&s, size](auto &v, auto i) IGUANA__INLINE_LAMBDA {
render_json_value(s, v);

if (i != size - 1)
if (i != size - 1) [[likely]]
s.push_back(',');
});
s.push_back(']');
Expand Down
30 changes: 29 additions & 1 deletion iguana/xml_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,30 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end,
parse_item(value.value(), it, end, name);
}

// /> or skip <?>、 <!> and <tag></tag> until the </name>
// loose inspection here
template <typename It>
IGUANA_INLINE void skip_object_value(It &&it, It &&end, std::string_view name) {
skip_till_greater(it, end);
++it;
if (*(it - 2) == '/') {
// .../>
return;
}
// </name>
size_t size = name.size();
while (it != end) {
skip_till_greater(it, end);
if (*(it - size - 2) == '<' && *(it - size - 1) == '/' &&
(std::string_view{&*(it - size), size} == name)) {
++it;
return;
}
++it;
}
throw std::runtime_error("unclosed tag: " + std::string(name));
}

template <refletable T, typename It>
IGUANA_INLINE void parse_item(T &value, It &&it, It &&end,
std::string_view name) {
Expand Down Expand Up @@ -241,12 +265,16 @@ IGUANA_INLINE void parse_item(T &value, It &&it, It &&end,
"type must be memberptr");
using V = std::remove_reference_t<decltype(value.*member_ptr)>;
if constexpr (!cdata_t<V>) {
detail::parse_item(value.*member_ptr, it, end, key);
parse_item(value.*member_ptr, it, end, key);
}
},
member_it->second);
} else [[unlikely]] {
#ifdef THROW_UNKNOWN_KEY
throw std::runtime_error("Unknown key: " + std::string(key));
#else
skip_object_value(it, end, key);
#endif
}
skip_sapces_and_newline(it, end);
}
Expand Down
80 changes: 80 additions & 0 deletions test/test_xml_nothrow.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#define DOCTEST_CONFIG_IMPLEMENT
#include "doctest.h"
#undef THROW_UNKNOWN_KEY
#include "iguana/xml_reader.hpp"
#include "iguana/xml_writer.hpp"
#include <deque>
#include <iostream>
#include <iterator>
#include <list>
#include <optional>
#include <vector>

enum class enum_status {
paid,
unpaid,
};
struct order_t {
enum_status status;
float total;
};
REFLECTION(order_t, status, total);

TEST_CASE("test unkonwn key") {
auto validator = [] (order_t od) {
CHECK(od.status == enum_status::unpaid);
CHECK(od.total == 65.0f);
};
std::string str = R"(
<order_t>
<orderID>12345</orderID>
<status>1</status>
<phone />
<customer>
<firstName>John</firstName>
<![CDATA[ node2</p>]]>
<lastName>Doe</lastName>
<address>
<street>123 Main St</street>
<city>Anytown</city>
<state>CA</state>
<zip>12345</zip>
</address>
</customer>
<items>
<item>
<productID>67890</productID>
<name>Widget A</name>
<quantity>2</quantity>
<price>10.00</price>
</item>
<item>
<productID>98765</productID>
<name>Widget B</name>
<quantity>3</quantity>
<price>15.00</price>
</item>
</items>
<![CDATA[ node2</p>]]>
<total>65.00</total>
</order_t>
)";
order_t od;
iguana::from_xml(od, str);
validator(od);

std::string ss;
iguana::to_xml(od, ss);
order_t od1;
iguana::from_xml(od1, ss);
validator(od1);
}



// doctest comments
// 'function' : must be 'attribute' - see issue #182
DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007)
int main(int argc, char **argv) { return doctest::Context(argc, argv).run(); }
DOCTEST_MSVC_SUPPRESS_WARNING_POP

0 comments on commit 21f4578

Please sign in to comment.