diff --git a/README.md b/README.md index 28b1f1e26..20da9bed2 100644 --- a/README.md +++ b/README.md @@ -55,8 +55,8 @@ int main() ```cpp CROW_ROUTE(app, "/json") ([]{ - crow::json::wvalue x; - x["message"] = "Hello, World!"; + crow::json::wvalue x({{"message", "Hello, World!"}}); + x["message2"] = "Hello, World.. Again!"; return x; }); ``` diff --git a/docs/guides/json.md b/docs/guides/json.md index 9ed7748a4..b1c6a744f 100644 --- a/docs/guides/json.md +++ b/docs/guides/json.md @@ -31,6 +31,8 @@ JSON write value, used for creating, editing and converting JSON to a string.

+Additionally, a `wvalue` can be initialized as an object using an initializer list, an example object would be `wvalue x = {{"a", 1}, {"b", 2}}`. Or as a list using `wvalue x = json::wvalue::list({1, 2, 3})`, lists can include any type that `wvalue` supports. + An object type `wvalue` uses `std::unordered_map` by default, if you want to have your returned `wvalue` key value pairs be sorted (using `std::map`) you can add `#!cpp #define CROW_JSON_USE_MAP` to the top of your program.

A JSON `wvalue` can be returned directly inside a route handler, this will cause the `content-type` header to automatically be set to `Application/json` and the JSON value will be converted to string and placed in the response body. For more information go to [Routes](../routes).

diff --git a/docs/overrides/home.html b/docs/overrides/home.html index 0fabf55f1..4491f5ed0 100644 --- a/docs/overrides/home.html +++ b/docs/overrides/home.html @@ -174,8 +174,8 @@

Easy to get started

CROW_ROUTE(app, "/json")
 ([]{
-    crow::json::wvalue x;
-    x["message"] = "Hello, World!";
+    crow::json::wvalue x{{"({{"}}"message", "Hello, World!"{{"}});"}}
+    x["message2"] = "Hello, World.. Again!";
     return x;
 });
 
diff --git a/docs/overrides/main.html b/docs/overrides/main.html index e3dfe8716..ab65d693e 100644 --- a/docs/overrides/main.html +++ b/docs/overrides/main.html @@ -6,4 +6,6 @@ + + {% endblock %} diff --git a/examples/example.cpp b/examples/example.cpp index 4b9edbfa8..5070695c0 100644 --- a/examples/example.cpp +++ b/examples/example.cpp @@ -63,11 +63,33 @@ int main() // simple json response - // To see it in action enter {ip}:18080/json CROW_ROUTE(app, "/json") ([]{ - crow::json::wvalue x; - x["message"] = "Hello, World!"; + crow::json::wvalue x({{"message", "Hello, World!"}}); + x["message2"] = "Hello, World.. Again!"; + return x; + }); + + CROW_ROUTE(app, "/json-initializer-list-constructor") + ([] { + return crow::json::wvalue({ + {"first", "Hello world!"}, /* stores a char const* hence a json::type::String */ + {"second", std::string("How are you today?")}, /* stores a std::string hence a json::type::String. */ + {"third", 54}, /* stores an int (as 54 is an int literal) hence a std::int64_t. */ + {"fourth", 54l}, /* stores a long (as 54l is a long literal) hence a std::int64_t. */ + {"fifth", 54u}, /* stores an unsigned int (as 54u is a unsigned int literal) hence a std::uint64_t. */ + {"sixth", 54ul}, /* stores an unsigned long (as 54ul is an unsigned long literal) hence a std::uint64_t. */ + {"seventh", 2.f}, /* stores a float (as 2.f is a float literal) hence a double. */ + {"eighth", 2.}, /* stores a double (as 2. is a double literal) hence a double. */ + {"ninth", nullptr}, /* stores a std::nullptr hence json::type::Null . */ + {"tenth", true} /* stores a bool hence json::type::True . */ + }); + }); + + // json list response + CROW_ROUTE(app, "/json_list") + ([]{ + crow::json::wvalue x(crow::json::wvalue::list({1,2,3})); return x; }); diff --git a/examples/example_json_map.cpp b/examples/example_json_map.cpp index 043035146..03b3d9238 100644 --- a/examples/example_json_map.cpp +++ b/examples/example_json_map.cpp @@ -11,31 +11,11 @@ int main() // it shoud show amessage before zmessage despite adding zmessage first. CROW_ROUTE(app, "/json") ([]{ - crow::json::wvalue x; - x["zmessage"] = "Hello, World!"; - x["amessage"] = "Hello, World2!"; + crow::json::wvalue x({{"zmessage", "Hello, World!"}, + {"amessage", "Hello, World2!"}}); return x; }); -CROW_ROUTE(app, "/json-initializer-list-constructor") -([] { - return crow::json::wvalue({ - {"first", "Hello world!"}, /* stores a char const* hence a json::type::String */ - {"second", std::string("How are you today?")}, /* stores a std::string hence a json::type::String. */ - {"third", 54}, /* stores an int (as 54 is an int literal) hence a std::int64_t. */ - {"fourth", 54l}, /* stores a long (as 54l is a long literal) hence a std::int64_t. */ - {"fifth", 54u}, /* stores an unsigned int (as 54u is a unsigned int literal) hence a std::uint64_t. */ - {"sixth", 54ul}, /* stores an unsigned long (as 54ul is an unsigned long literal) hence a std::uint64_t. */ - {"seventh", 2.f}, /* stores a float (as 2.f is a float literal) hence a double. */ - {"eighth", 2.}, /* stores a double (as 2. is a double literal) hence a double. */ - {"ninth", nullptr}, /* stores a std::nullptr hence json::type::Null . */ - {"tenth", true} /* stores a bool hence json::type::True . */ - }); -}); - -// enables all log -app.loglevel(crow::LogLevel::Debug); - app.port(18080) .multithreaded() .run(); diff --git a/examples/example_with_all.cpp b/examples/example_with_all.cpp index a015e6b3a..2ab5fc8b8 100644 --- a/examples/example_with_all.cpp +++ b/examples/example_with_all.cpp @@ -28,8 +28,31 @@ int main() // simple json response CROW_ROUTE(app, "/json") ([]{ - crow::json::wvalue x; - x["message"] = "Hello, World!"; + crow::json::wvalue x({{"message", "Hello, World!"}}); + x["message2"] = "Hello, World.. Again!"; + return x; + }); + + CROW_ROUTE(app, "/json-initializer-list-constructor") + ([] { + return crow::json::wvalue({ + {"first", "Hello world!"}, /* stores a char const* hence a json::type::String */ + {"second", std::string("How are you today?")}, /* stores a std::string hence a json::type::String. */ + {"third", 54}, /* stores an int (as 54 is an int literal) hence a std::int64_t. */ + {"fourth", 54l}, /* stores a long (as 54l is a long literal) hence a std::int64_t. */ + {"fifth", 54u}, /* stores an unsigned int (as 54u is a unsigned int literal) hence a std::uint64_t. */ + {"sixth", 54ul}, /* stores an unsigned long (as 54ul is an unsigned long literal) hence a std::uint64_t. */ + {"seventh", 2.f}, /* stores a float (as 2.f is a float literal) hence a double. */ + {"eighth", 2.}, /* stores a double (as 2. is a double literal) hence a double. */ + {"ninth", nullptr}, /* stores a std::nullptr hence json::type::Null . */ + {"tenth", true} /* stores a bool hence json::type::True . */ + }); + }); + + // json list response + CROW_ROUTE(app, "/json_list") + ([]{ + crow::json::wvalue x(crow::json::wvalue::list({1,2,3})); return x; }); diff --git a/examples/helloworld.cpp b/examples/helloworld.cpp index 116f7559c..c12b8c41e 100644 --- a/examples/helloworld.cpp +++ b/examples/helloworld.cpp @@ -7,7 +7,7 @@ int main() CROW_ROUTE(app, "/") ([]() { - return "Hello world!"; + return "Hello, world!"; }); app.port(18080).run(); diff --git a/include/crow/json.h b/include/crow/json.h index 04a6209ae..be7ac8d91 100644 --- a/include/crow/json.h +++ b/include/crow/json.h @@ -1216,6 +1216,7 @@ namespace crow return load(str.data(), str.size()); } + /// JSON write value. /// @@ -1226,14 +1227,16 @@ namespace crow friend class crow::mustache::template_t; public: - using object_type = + + using object = #ifdef CROW_JSON_USE_MAP std::map; #else std::unordered_map; #endif - public: + using list = std::vector; + type t() const { return t_; } private: type t_{type::Null}; ///< The type of the value. @@ -1250,12 +1253,8 @@ namespace crow constexpr number(double value) noexcept : d(value) {} } num; ///< Value if type is a number. std::string s; ///< Value if type is a string. - std::unique_ptr> l; ///< Value if type is a list. -#ifdef CROW_JSON_USE_MAP - std::unique_ptr> o; -#else - std::unique_ptr> o; ///< Value if type is a JSON object. -#endif + std::unique_ptr l; ///< Value if type is a list. + std::unique_ptr o; ///< Value if type is a JSON object. public: wvalue() : returnable("application/json") {} @@ -1282,15 +1281,23 @@ namespace crow wvalue(std::string const& value) : returnable("application/json"), t_(type::String), s(value) {} wvalue(std::string&& value) : returnable("application/json"), t_(type::String), s(std::move(value)) {} - wvalue(std::initializer_list> initializer_list) : returnable("application/json"), t_(type::Object), o(new object_type(initializer_list)) {} + wvalue(std::initializer_list> initializer_list) : returnable("application/json"), t_(type::Object), o(new object(initializer_list)) {} - wvalue(object_type const& value) : returnable("application/json"), t_(type::Object), o(new object_type(value)) {} - wvalue(object_type&& value) : returnable("application/json"), t_(type::Object), o(new object_type(std::move(value))) {} + wvalue(object const& value) : returnable("application/json"), t_(type::Object), o(new object(value)) {} + wvalue(object&& value) : returnable("application/json"), t_(type::Object), o(new object(std::move(value))) {} - wvalue(std::vector& r) : returnable("application/json") + wvalue(const list& r) : returnable("application/json") + { + t_ = type::List; + l = std::unique_ptr(new list{}); + l->reserve(r.size()); + for(auto it = r.begin(); it != r.end(); ++it) + l->emplace_back(*it); + } + wvalue(list& r) : returnable("application/json") { t_ = type::List; - l = std::unique_ptr>(new std::vector{}); + l = std::unique_ptr(new list{}); l->reserve(r.size()); for(auto it = r.begin(); it != r.end(); ++it) l->emplace_back(*it); @@ -1319,17 +1326,13 @@ namespace crow s = r.s(); return; case type::List: - l = std::unique_ptr>(new std::vector{}); + l = std::unique_ptr(new list{}); l->reserve(r.size()); for(auto it = r.begin(); it != r.end(); ++it) l->emplace_back(*it); return; case type::Object: -#ifdef CROW_JSON_USE_MAP - o = std::unique_ptr>(new std::map{}); -#else - o = std::unique_ptr>(new std::unordered_map{}); -#endif + o = std::unique_ptr(new object{}); for(auto it = r.begin(); it != r.end(); ++it) o->emplace(it->key(), *it); return; @@ -1358,17 +1361,13 @@ namespace crow s = r.s; return; case type::List: - l = std::unique_ptr>(new std::vector{}); + l = std::unique_ptr(new list{}); l->reserve(r.size()); for(auto it = r.l->begin(); it != r.l->end(); ++it) l->emplace_back(*it); return; case type::Object: -#ifdef CROW_JSON_USE_MAP - o = std::unique_ptr>(new std::map{}); -#else - o = std::unique_ptr>(new std::unordered_map{}); -#endif + o = std::unique_ptr(new object{}); o->insert(r.o->begin(), r.o->end()); return; } @@ -1514,13 +1513,13 @@ namespace crow return *this; } - wvalue& operator=(std::vector&& v) + wvalue& operator=(list&& v) { if (t_ != type::List) reset(); t_ = type::List; if (!l) - l = std::unique_ptr>(new std::vector{}); + l = std::unique_ptr(new list{}); l->clear(); l->resize(v.size()); size_t idx = 0; @@ -1538,7 +1537,7 @@ namespace crow reset(); t_ = type::List; if (!l) - l = std::unique_ptr>(new std::vector{}); + l = std::unique_ptr(new list{}); l->clear(); l->resize(v.size()); size_t idx = 0; @@ -1554,31 +1553,31 @@ namespace crow if (t_ != type::Object) { reset(); t_ = type::Object; - o = std::unique_ptr(new object_type(initializer_list)); + o = std::unique_ptr(new object(initializer_list)); } else { (*o) = initializer_list; } return *this; } - wvalue& operator=(object_type const& value) + wvalue& operator=(object const& value) { if (t_ != type::Object) { reset(); t_ = type::Object; - o = std::unique_ptr(new object_type(value)); + o = std::unique_ptr(new object(value)); } else { (*o) = value; } return *this; } - wvalue& operator=(object_type&& value) + wvalue& operator=(object&& value) { if (t_ != type::Object) { reset(); t_ = type::Object; - o = std::unique_ptr(new object_type(std::move(value))); + o = std::unique_ptr(new object(std::move(value))); } else { (*o) = std::move(value); } @@ -1591,7 +1590,7 @@ namespace crow reset(); t_ = type::List; if (!l) - l = std::unique_ptr>(new std::vector{}); + l = std::unique_ptr(new list{}); if (l->size() < index+1) l->resize(index+1); return (*l)[index]; @@ -1612,11 +1611,7 @@ namespace crow reset(); t_ = type::Object; if (!o) -#ifdef CROW_JSON_USE_MAP - o = std::unique_ptr>(new std::map{}); -#else - o = std::unique_ptr>(new std::unordered_map{}); -#endif + o = std::unique_ptr(new object{}); return (*o)[str]; } @@ -1706,8 +1701,48 @@ namespace crow #else #define MSC_COMPATIBLE_SPRINTF(BUFFER_PTR, FORMAT_PTR, VALUE) sprintf((BUFFER_PTR), (FORMAT_PTR), (VALUE)) #endif + enum { + start, + decp, + zero + } f_state; char outbuf[128]; - MSC_COMPATIBLE_SPRINTF(outbuf, "%g", v.num.d); + MSC_COMPATIBLE_SPRINTF(outbuf, "%f", v.num.d); + char *p = &outbuf[0], *o = nullptr; + f_state = start; + while (*p != '\0') + { + //std::cout << *p << std::endl; + char ch = *p; + switch (f_state){ + case start: + if (ch == '.') + { + if (p+1 && *(p+1) == '0') p++; + f_state = decp; + } + p++; + break; + case decp: + if (ch == '0') + { + f_state = zero; + o = p; + } + p++; + break; + case zero: + if (ch != '0') + { + o = nullptr; + f_state = decp; + } + p++; + break; + } + } + if (o != nullptr) + *o = '\0'; out += outbuf; #undef MSC_COMPATIBLE_SPRINTF } diff --git a/include/crow/middlewares/utf-8.h b/include/crow/middlewares/utf-8.h index 909c9a2de..d0cce2498 100644 --- a/include/crow/middlewares/utf-8.h +++ b/include/crow/middlewares/utf-8.h @@ -15,7 +15,7 @@ namespace crow { } - void after_handle(request& /*req*/, response& res, context& ctx) + void after_handle(request& /*req*/, response& res, context& /*ctx*/) { if (get_header_value(res.headers, "Content-Type").empty()) { diff --git a/tests/unittest.cpp b/tests/unittest.cpp index ebb15c854..8bc39ae1e 100644 --- a/tests/unittest.cpp +++ b/tests/unittest.cpp @@ -746,6 +746,8 @@ TEST_CASE("json_copy_r_to_w_to_w_to_r") CHECK("other" == x["obj"]["other"].key()); } +//TODO maybe combine these + TEST_CASE("json::wvalue::wvalue(bool)") { CHECK(json::wvalue(true).t() == json::type::True); CHECK(json::wvalue(false).t() == json::type::False); @@ -885,7 +887,7 @@ TEST_CASE("json::wvalue::wvalue(std::[unordered_]map truth = true; lie = false; - json::wvalue::object_type map({ + json::wvalue::object map({ {"integer", integer}, {"number", number}, {"truth", truth}, @@ -909,7 +911,7 @@ TEST_CASE("json::wvalue::wvalue(std::[unordered_]map& truth = true; lie = false; - json::wvalue::object_type map = {{ + json::wvalue::object map = {{ {"integer", integer}, {"number", number}, {"truth", truth}, @@ -958,7 +960,7 @@ TEST_CASE("json::wvalue::operator=(std::[unordered_]map