Skip to content

Commit

Permalink
Merge pull request #203 from CrowCpp/json_additions
Browse files Browse the repository at this point in the history
Several JSON addition
  • Loading branch information
The-EDev authored Aug 20, 2021
2 parents 526fd75 + f533826 commit a3ef00f
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 78 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});
```
Expand Down
2 changes: 2 additions & 0 deletions docs/guides/json.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ JSON write value, used for creating, editing and converting JSON to a string.<br

A `wvalue` can be treated as an object or even a list (setting a value by using `json[3] = 32` for example). Please note that this will remove the data in the value if it isn't of List type.<br><br>

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.<br><br>

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).<br><br>
Expand Down
4 changes: 2 additions & 2 deletions docs/overrides/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ <h2 style="text-align: center;">Easy to get started</h3>
<div class="scontent">
<div class="highlight"><pre id="__code_1"><span></span><button class="md-clipboard md-icon" title="Copy to clipboard" data-clipboard-target="#__code_1 > code"></button><code><span class="cp">CROW_ROUTE</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="s">"/json"</span><span class="p">)</span>
<span class="p">([]{</span>
<span class="n">crow</span><span class="o">::</span><span class="n">json</span><span class="o">::</span><span class="n">wvalue</span> <span class="n">x</span><span class="p">;</span>
<span class="n">x</span><span class="p">[</span><span class="s">"message"</span><span class="p">]</span> <span class="o">=</span> <span class="s">"Hello, World!"</span><span class="p">;</span>
<span class="n">crow</span><span class="o">::</span><span class="n">json</span><span class="o">::</span><span class="n">wvalue</span> <span class="n">x</span><span class="p">{{"({{"}}</span><span class="s">"message"</span><span class="p">,</span> <span class="s">"Hello, World!"</span><span class="p">{{"}});"}}</span>
<span class="n">x</span><span class="p">[</span><span class="s">"message2"</span><span class="p">]</span> <span class="o">=</span> <span class="s">"Hello, World.. Again!"</span><span class="p">;</span>
<span class="k">return</span> <span class="n">x</span><span class="p">;</span>
<span class="p">});</span>
</code></pre></div>
Expand Down
2 changes: 2 additions & 0 deletions docs/overrides/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
<meta property="og:description" content="A Fast and Easy to use microframework for the web."/>
<meta property="og:image" content="/assets/og_img.png" />
<meta property="og:url" content="https://crowcpp.org">
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:image" content="/assets/og_img.png">
{% endblock %}
28 changes: 25 additions & 3 deletions examples/example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});

Expand Down
24 changes: 2 additions & 22 deletions examples/example_json_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
27 changes: 25 additions & 2 deletions examples/example_with_all.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
});

Expand Down
2 changes: 1 addition & 1 deletion examples/helloworld.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ int main()

CROW_ROUTE(app, "/")
([]() {
return "Hello world!";
return "Hello, world!";
});

app.port(18080).run();
Expand Down
115 changes: 75 additions & 40 deletions include/crow/json.h
Original file line number Diff line number Diff line change
Expand Up @@ -1216,6 +1216,7 @@ namespace crow
return load(str.data(), str.size());
}


/// JSON write value.

///
Expand All @@ -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<std::string, wvalue>;
#else
std::unordered_map<std::string, wvalue>;
#endif

public:
using list = std::vector<wvalue>;

type t() const { return t_; }
private:
type t_{type::Null}; ///< The type of the value.
Expand All @@ -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<std::vector<wvalue>> l; ///< Value if type is a list.
#ifdef CROW_JSON_USE_MAP
std::unique_ptr<std::map<std::string, wvalue>> o;
#else
std::unique_ptr<std::unordered_map<std::string, wvalue>> o; ///< Value if type is a JSON object.
#endif
std::unique_ptr<list> l; ///< Value if type is a list.
std::unique_ptr<object> o; ///< Value if type is a JSON object.

public:
wvalue() : returnable("application/json") {}
Expand All @@ -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<std::pair<std::string const, wvalue>> initializer_list) : returnable("application/json"), t_(type::Object), o(new object_type(initializer_list)) {}
wvalue(std::initializer_list<std::pair<std::string const, wvalue>> 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<wvalue>& r) : returnable("application/json")
wvalue(const list& r) : returnable("application/json")
{
t_ = type::List;
l = std::unique_ptr<list>(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<std::vector<wvalue>>(new std::vector<wvalue>{});
l = std::unique_ptr<list>(new list{});
l->reserve(r.size());
for(auto it = r.begin(); it != r.end(); ++it)
l->emplace_back(*it);
Expand Down Expand Up @@ -1319,17 +1326,13 @@ namespace crow
s = r.s();
return;
case type::List:
l = std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{});
l = std::unique_ptr<list>(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<std::map<std::string, wvalue>>(new std::map<std::string, wvalue>{});
#else
o = std::unique_ptr<std::unordered_map<std::string, wvalue>>(new std::unordered_map<std::string, wvalue>{});
#endif
o = std::unique_ptr<object>(new object{});
for(auto it = r.begin(); it != r.end(); ++it)
o->emplace(it->key(), *it);
return;
Expand Down Expand Up @@ -1358,17 +1361,13 @@ namespace crow
s = r.s;
return;
case type::List:
l = std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{});
l = std::unique_ptr<list>(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<std::map<std::string, wvalue>>(new std::map<std::string, wvalue>{});
#else
o = std::unique_ptr<std::unordered_map<std::string, wvalue>>(new std::unordered_map<std::string, wvalue>{});
#endif
o = std::unique_ptr<object>(new object{});
o->insert(r.o->begin(), r.o->end());
return;
}
Expand Down Expand Up @@ -1514,13 +1513,13 @@ namespace crow
return *this;
}

wvalue& operator=(std::vector<wvalue>&& v)
wvalue& operator=(list&& v)
{
if (t_ != type::List)
reset();
t_ = type::List;
if (!l)
l = std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{});
l = std::unique_ptr<list>(new list{});
l->clear();
l->resize(v.size());
size_t idx = 0;
Expand All @@ -1538,7 +1537,7 @@ namespace crow
reset();
t_ = type::List;
if (!l)
l = std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{});
l = std::unique_ptr<list>(new list{});
l->clear();
l->resize(v.size());
size_t idx = 0;
Expand All @@ -1554,31 +1553,31 @@ namespace crow
if (t_ != type::Object) {
reset();
t_ = type::Object;
o = std::unique_ptr<object_type>(new object_type(initializer_list));
o = std::unique_ptr<object>(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<object_type>(new object_type(value));
o = std::unique_ptr<object>(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<object_type>(new object_type(std::move(value)));
o = std::unique_ptr<object>(new object(std::move(value)));
} else {
(*o) = std::move(value);
}
Expand All @@ -1591,7 +1590,7 @@ namespace crow
reset();
t_ = type::List;
if (!l)
l = std::unique_ptr<std::vector<wvalue>>(new std::vector<wvalue>{});
l = std::unique_ptr<list>(new list{});
if (l->size() < index+1)
l->resize(index+1);
return (*l)[index];
Expand All @@ -1612,11 +1611,7 @@ namespace crow
reset();
t_ = type::Object;
if (!o)
#ifdef CROW_JSON_USE_MAP
o = std::unique_ptr<std::map<std::string, wvalue>>(new std::map<std::string, wvalue>{});
#else
o = std::unique_ptr<std::unordered_map<std::string, wvalue>>(new std::unordered_map<std::string, wvalue>{});
#endif
o = std::unique_ptr<object>(new object{});
return (*o)[str];
}

Expand Down Expand Up @@ -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
}
Expand Down
Loading

0 comments on commit a3ef00f

Please sign in to comment.