Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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