Browse Source

cutelyst: Asql version update and picoJSON usage on JSON test (#6705)

* Cutelyst: Update ASql to v0.43.0

* cutelyst: Add JSON test with PicoJSON
Daniel Nicoletti 4 years ago
parent
commit
737ec11132

+ 17 - 0
frameworks/C++/cutelyst/benchmark_config.json

@@ -114,6 +114,23 @@
                 "notes": "",
                 "notes": "",
                 "versus": ""
                 "versus": ""
             },
             },
+            "thread-pico": {
+                "json_url": "/pson",
+                "port": 8080,
+                "approach": "Realistic",
+                "classification": "Fullstack",
+                "database": "None",
+                "framework": "cutelyst",
+                "language": "C++",
+                "orm": "Raw",
+                "platform": "CutelystWSGI",
+                "webserver": "None",
+                "os": "Linux",
+                "database_os": "Linux",
+                "display_name": "cutelyst-pico",
+                "notes": "",
+                "versus": ""
+            },
             "thread-apg": {
             "thread-apg": {
                 "db_url": "/dbp",
                 "db_url": "/dbp",
                 "query_url": "/queriesp?queries=",
                 "query_url": "/queriesp?queries=",

+ 1 - 1
frameworks/C++/cutelyst/build.sh

@@ -1,6 +1,6 @@
 #!/bin/bash
 #!/bin/bash
 
 
-export ASQL_VER=0.26.0
+export ASQL_VER=0.43.0
 export CUTELEE_VER=5.3.0
 export CUTELEE_VER=5.3.0
 export CUTELYST_VER=2.14.0
 export CUTELYST_VER=2.14.0
 
 

+ 12 - 0
frameworks/C++/cutelyst/config.toml

@@ -53,6 +53,18 @@ platform = "CutelystWSGI"
 webserver = "None"
 webserver = "None"
 versus = ""
 versus = ""
 
 
+[thread-pico]
+urls.json = "/pson"
+approach = "Realistic"
+classification = "Fullstack"
+database = "None"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "CutelystWSGI"
+webserver = "None"
+versus = ""
+
 [main]
 [main]
 urls.plaintext = "/plaintext"
 urls.plaintext = "/plaintext"
 urls.json = "/json"
 urls.json = "/json"

+ 39 - 0
frameworks/C++/cutelyst/cutelyst-thread-pico.dockerfile

@@ -0,0 +1,39 @@
+FROM ubuntu:20.04
+
+RUN apt-get update -qq && \
+    apt-get install -yqq locales wget build-essential
+
+RUN locale-gen en_US.UTF-8
+ENV LANG en_US.UTF-8
+ENV LANGUAGE en_US:en
+ENV LC_ALL en_US.UTF-8
+ENV DEBIAN_FRONTEND noninteractive
+
+ENV TROOT /cutelyst-benchmark-app
+ENV CUTELYST_APP ${TROOT}/build/libcutelyst_benchmarks.so
+
+COPY src ${TROOT}/
+
+COPY build.sh .
+RUN ./build.sh
+
+COPY config/config.ini /cutelyst.ini
+COPY config/config_socket.ini /cutelyst_socket.ini
+COPY nginx.conf /nginx.conf
+
+RUN sed -i "s|DatabaseHostName=.*|DatabaseHostName=tfb-database|g" /cutelyst.ini
+RUN sed -i "s|DatabaseHostName=.*|DatabaseHostName=tfb-database|g" /cutelyst_socket.ini
+
+ENV C_PROCESSES 1
+ENV CPU_AFFINITY 1
+
+EXPOSE 8080
+
+CMD cutelyst-wsgi2 \
+    --ini /cutelyst.ini:uwsgi \
+    --application ${CUTELYST_APP} \
+    --processes=${C_PROCESSES} \
+    --threads=$(nproc) \
+    --cpu-affinity=${CPU_AFFINITY} \
+    --socket-timeout 0 \
+    --reuse-port

+ 4 - 4
frameworks/C++/cutelyst/src/databaseupdatestest.cpp

@@ -41,14 +41,14 @@ void DatabaseUpdatesTest::updatep(Context *c)
                          {QStringLiteral("randomNumber"), randomNumber}
                          {QStringLiteral("randomNumber"), randomNumber}
                      });
                      });
 
 
-        db.execPrepared(APreparedQueryLiteral("SELECT randomNumber, id FROM world WHERE id=$1"),
+        db.exec(APreparedQueryLiteral(u"SELECT randomNumber, id FROM world WHERE id=$1"),
                                {id}, [c, async] (AResult &result) {
                                {id}, [c, async] (AResult &result) {
             if (Q_UNLIKELY(result.error() || !result.size())) {
             if (Q_UNLIKELY(result.error() || !result.size())) {
                 c->res()->setStatus(Response::InternalServerError);
                 c->res()->setStatus(Response::InternalServerError);
                 return;
                 return;
             }
             }
         }, c);
         }, c);
-        db.execPrepared(APreparedQueryLiteral("UPDATE world SET randomNumber=$1 WHERE id=$2"),
+        db.exec(APreparedQueryLiteral(u"UPDATE world SET randomNumber=$1 WHERE id=$2"),
                                {randomNumber, id}, [c, async] (AResult &result) {
                                {randomNumber, id}, [c, async] (AResult &result) {
             if (Q_UNLIKELY(result.error())) {
             if (Q_UNLIKELY(result.error())) {
                 c->res()->setStatus(Response::InternalServerError);
                 c->res()->setStatus(Response::InternalServerError);
@@ -89,7 +89,7 @@ void DatabaseUpdatesTest::updateb(Context *c)
                          {QStringLiteral("randomNumber"), randomNumber}
                          {QStringLiteral("randomNumber"), randomNumber}
                      });
                      });
 
 
-        db.execPrepared(APreparedQueryLiteral("SELECT randomNumber, id FROM world WHERE id=$1"),
+        db.exec(APreparedQueryLiteral(u"SELECT randomNumber, id FROM world WHERE id=$1"),
                                {id}, [c, async] (AResult &result) {
                                {id}, [c, async] (AResult &result) {
             if (Q_UNLIKELY(result.error() || !result.size())) {
             if (Q_UNLIKELY(result.error() || !result.size())) {
                 c->res()->setStatus(Response::InternalServerError);
                 c->res()->setStatus(Response::InternalServerError);
@@ -100,7 +100,7 @@ void DatabaseUpdatesTest::updateb(Context *c)
     args.append(argsIds);
     args.append(argsIds);
 
 
     const APreparedQuery pq = getSql(queries);
     const APreparedQuery pq = getSql(queries);
-    db.execPrepared(pq, args, [c, async] (AResult &result) {
+    db.exec(pq, args, [c, async] (AResult &result) {
         if (Q_UNLIKELY(result.error())) {
         if (Q_UNLIKELY(result.error())) {
             c->res()->setStatus(Response::InternalServerError);
             c->res()->setStatus(Response::InternalServerError);
             return;
             return;

+ 2 - 2
frameworks/C++/cutelyst/src/fortunetest.cpp

@@ -18,7 +18,7 @@ void FortuneTest::fortunes_raw_p(Context *c)
 {
 {
     ASync async(c);
     ASync async(c);
     static thread_local auto db = APool::database();
     static thread_local auto db = APool::database();
-    db.execPrepared(APreparedQueryLiteral("SELECT id, message FROM fortune"), [c, async, this] (AResult &result) {
+    db.exec(APreparedQueryLiteral(u"SELECT id, message FROM fortune"), [c, async, this] (AResult &result) {
         if (Q_UNLIKELY(result.error() && !result.size())) {
         if (Q_UNLIKELY(result.error() && !result.size())) {
             c->res()->setStatus(Response::InternalServerError);
             c->res()->setStatus(Response::InternalServerError);
             return;
             return;
@@ -63,7 +63,7 @@ void FortuneTest::fortunes_c_p(Context *c)
 {
 {
     ASync async(c);
     ASync async(c);
     static thread_local auto db = APool::database();
     static thread_local auto db = APool::database();
-    db.execPrepared(APreparedQueryLiteral("SELECT id, message FROM fortune"), [c, async] (AResult &result) {
+    db.exec(APreparedQueryLiteral(u"SELECT id, message FROM fortune"), [c, async] (AResult &result) {
         if (Q_UNLIKELY(result.error() && !result.size())) {
         if (Q_UNLIKELY(result.error() && !result.size())) {
             c->res()->setStatus(Response::InternalServerError);
             c->res()->setStatus(Response::InternalServerError);
             return;
             return;

+ 10 - 0
frameworks/C++/cutelyst/src/jsontest.cpp

@@ -1,5 +1,7 @@
 #include "jsontest.h"
 #include "jsontest.h"
 
 
+#include "picojson.h"
+
 #include <QJsonDocument>
 #include <QJsonDocument>
 #include <QJsonObject>
 #include <QJsonObject>
 
 
@@ -12,3 +14,11 @@ void JsonTest::json(Context *c)
 {
 {
     c->response()->setJsonObjectBody({ {QStringLiteral("message"), QStringLiteral("Hello, World!")} });
     c->response()->setJsonObjectBody({ {QStringLiteral("message"), QStringLiteral("Hello, World!")} });
 }
 }
+
+void JsonTest::pson(Context *c)
+{
+    c->response()->setJsonBody(QByteArray::fromStdString(
+                                picojson::value(picojson::object{
+                                                    {"message", picojson::value("Hello, World!")}
+                                                }).serialize()));
+}

+ 3 - 0
frameworks/C++/cutelyst/src/jsontest.h

@@ -14,6 +14,9 @@ public:
 
 
     C_ATTR(json, :Local :AutoArgs)
     C_ATTR(json, :Local :AutoArgs)
     void json(Context *c);
     void json(Context *c);
+
+    C_ATTR(pson, :Local :AutoArgs)
+    void pson(Context *c);
 };
 };
 
 
 #endif // JSONTEST_H
 #endif // JSONTEST_H

+ 1 - 1
frameworks/C++/cutelyst/src/multipledatabasequeriestest.cpp

@@ -32,7 +32,7 @@ void MultipleDatabaseQueriesTest::queriesp(Context *c)
     for (int i = 0; i < queries; ++i) {
     for (int i = 0; i < queries; ++i) {
         const int id = (qrand() % 10000) + 1;
         const int id = (qrand() % 10000) + 1;
 
 
-        db.execPrepared(APreparedQueryLiteral("SELECT id, randomNumber FROM world WHERE id=$1"),
+        db.exec(APreparedQueryLiteral(u"SELECT id, randomNumber FROM world WHERE id=$1"),
                                {id}, [c, async, i, queries, array] (AResult &result) {
                                {id}, [c, async, i, queries, array] (AResult &result) {
             if (Q_LIKELY(!result.error() && result.size())) {
             if (Q_LIKELY(!result.error() && result.size())) {
                 auto it = result.begin();
                 auto it = result.begin();

+ 1200 - 0
frameworks/C++/cutelyst/src/picojson.h

@@ -0,0 +1,1200 @@
+/*
+ * Copyright 2009-2010 Cybozu Labs, Inc.
+ * Copyright 2011-2014 Kazuho Oku
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ *    this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef picojson_h
+#define picojson_h
+
+#include <algorithm>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cstddef>
+#include <iostream>
+#include <iterator>
+#include <limits>
+#include <map>
+#include <stdexcept>
+#include <string>
+#include <vector>
+#include <utility>
+
+// for isnan/isinf
+#if __cplusplus >= 201103L
+#include <cmath>
+#else
+extern "C" {
+#ifdef _MSC_VER
+#include <float.h>
+#elif defined(__INTEL_COMPILER)
+#include <mathimf.h>
+#else
+#include <math.h>
+#endif
+}
+#endif
+
+#ifndef PICOJSON_USE_RVALUE_REFERENCE
+#if (defined(__cpp_rvalue_references) && __cpp_rvalue_references >= 200610) || (defined(_MSC_VER) && _MSC_VER >= 1600)
+#define PICOJSON_USE_RVALUE_REFERENCE 1
+#else
+#define PICOJSON_USE_RVALUE_REFERENCE 0
+#endif
+#endif // PICOJSON_USE_RVALUE_REFERENCE
+
+#ifndef PICOJSON_NOEXCEPT
+#if PICOJSON_USE_RVALUE_REFERENCE
+#define PICOJSON_NOEXCEPT noexcept
+#else
+#define PICOJSON_NOEXCEPT throw()
+#endif
+#endif
+
+// experimental support for int64_t (see README.mkdn for detail)
+#ifdef PICOJSON_USE_INT64
+#define __STDC_FORMAT_MACROS
+#include <cerrno>
+#if __cplusplus >= 201103L
+#include <cinttypes>
+#else
+extern "C" {
+#include <inttypes.h>
+}
+#endif
+#endif
+
+// to disable the use of localeconv(3), set PICOJSON_USE_LOCALE to 0
+#ifndef PICOJSON_USE_LOCALE
+#define PICOJSON_USE_LOCALE 1
+#endif
+#if PICOJSON_USE_LOCALE
+extern "C" {
+#include <locale.h>
+}
+#endif
+
+#ifndef PICOJSON_ASSERT
+#define PICOJSON_ASSERT(e)                                                                                                         \
+  do {                                                                                                                             \
+    if (!(e))                                                                                                                      \
+      throw std::runtime_error(#e);                                                                                                \
+  } while (0)
+#endif
+
+#ifdef _MSC_VER
+#define SNPRINTF _snprintf_s
+#pragma warning(push)
+#pragma warning(disable : 4244) // conversion from int to char
+#pragma warning(disable : 4127) // conditional expression is constant
+#pragma warning(disable : 4702) // unreachable code
+#pragma warning(disable : 4706) // assignment within conditional expression
+#else
+#define SNPRINTF snprintf
+#endif
+
+namespace picojson {
+
+enum {
+  null_type,
+  boolean_type,
+  number_type,
+  string_type,
+  array_type,
+  object_type
+#ifdef PICOJSON_USE_INT64
+  ,
+  int64_type
+#endif
+};
+
+enum { INDENT_WIDTH = 2, DEFAULT_MAX_DEPTHS = 100 };
+
+struct null {};
+
+class value {
+public:
+  typedef std::vector<value> array;
+  typedef std::map<std::string, value> object;
+  union _storage {
+    bool boolean_;
+    double number_;
+#ifdef PICOJSON_USE_INT64
+    int64_t int64_;
+#endif
+    std::string *string_;
+    array *array_;
+    object *object_;
+  };
+
+protected:
+  int type_;
+  _storage u_;
+
+public:
+  value();
+  value(int type, bool);
+  explicit value(bool b);
+#ifdef PICOJSON_USE_INT64
+  explicit value(int64_t i);
+#endif
+  explicit value(double n);
+  explicit value(const std::string &s);
+  explicit value(const array &a);
+  explicit value(const object &o);
+#if PICOJSON_USE_RVALUE_REFERENCE
+  explicit value(std::string &&s);
+  explicit value(array &&a);
+  explicit value(object &&o);
+#endif
+  explicit value(const char *s);
+  value(const char *s, size_t len);
+  ~value();
+  value(const value &x);
+  value &operator=(const value &x);
+#if PICOJSON_USE_RVALUE_REFERENCE
+  value(value &&x) PICOJSON_NOEXCEPT;
+  value &operator=(value &&x) PICOJSON_NOEXCEPT;
+#endif
+  void swap(value &x) PICOJSON_NOEXCEPT;
+  template <typename T> bool is() const;
+  template <typename T> const T &get() const;
+  template <typename T> T &get();
+  template <typename T> void set(const T &);
+#if PICOJSON_USE_RVALUE_REFERENCE
+  template <typename T> void set(T &&);
+#endif
+  bool evaluate_as_boolean() const;
+  const value &get(const size_t idx) const;
+  const value &get(const std::string &key) const;
+  value &get(const size_t idx);
+  value &get(const std::string &key);
+
+  bool contains(const size_t idx) const;
+  bool contains(const std::string &key) const;
+  std::string to_str() const;
+  template <typename Iter> void serialize(Iter os, bool prettify = false) const;
+  std::string serialize(bool prettify = false) const;
+
+private:
+  template <typename T> value(const T *); // intentionally defined to block implicit conversion of pointer to bool
+  template <typename Iter> static void _indent(Iter os, int indent);
+  template <typename Iter> void _serialize(Iter os, int indent) const;
+  std::string _serialize(int indent) const;
+  void clear();
+};
+
+typedef value::array array;
+typedef value::object object;
+
+inline value::value() : type_(null_type), u_() {
+}
+
+inline value::value(int type, bool) : type_(type), u_() {
+  switch (type) {
+#define INIT(p, v)                                                                                                                 \
+  case p##type:                                                                                                                    \
+    u_.p = v;                                                                                                                      \
+    break
+    INIT(boolean_, false);
+    INIT(number_, 0.0);
+#ifdef PICOJSON_USE_INT64
+    INIT(int64_, 0);
+#endif
+    INIT(string_, new std::string());
+    INIT(array_, new array());
+    INIT(object_, new object());
+#undef INIT
+  default:
+    break;
+  }
+}
+
+inline value::value(bool b) : type_(boolean_type), u_() {
+  u_.boolean_ = b;
+}
+
+#ifdef PICOJSON_USE_INT64
+inline value::value(int64_t i) : type_(int64_type), u_() {
+  u_.int64_ = i;
+}
+#endif
+
+inline value::value(double n) : type_(number_type), u_() {
+  if (
+#ifdef _MSC_VER
+      !_finite(n)
+#elif __cplusplus >= 201103L
+      std::isnan(n) || std::isinf(n)
+#else
+      isnan(n) || isinf(n)
+#endif
+          ) {
+    throw std::overflow_error("");
+  }
+  u_.number_ = n;
+}
+
+inline value::value(const std::string &s) : type_(string_type), u_() {
+  u_.string_ = new std::string(s);
+}
+
+inline value::value(const array &a) : type_(array_type), u_() {
+  u_.array_ = new array(a);
+}
+
+inline value::value(const object &o) : type_(object_type), u_() {
+  u_.object_ = new object(o);
+}
+
+#if PICOJSON_USE_RVALUE_REFERENCE
+inline value::value(std::string &&s) : type_(string_type), u_() {
+  u_.string_ = new std::string(std::move(s));
+}
+
+inline value::value(array &&a) : type_(array_type), u_() {
+  u_.array_ = new array(std::move(a));
+}
+
+inline value::value(object &&o) : type_(object_type), u_() {
+  u_.object_ = new object(std::move(o));
+}
+#endif
+
+inline value::value(const char *s) : type_(string_type), u_() {
+  u_.string_ = new std::string(s);
+}
+
+inline value::value(const char *s, size_t len) : type_(string_type), u_() {
+  u_.string_ = new std::string(s, len);
+}
+
+inline void value::clear() {
+  switch (type_) {
+#define DEINIT(p)                                                                                                                  \
+  case p##type:                                                                                                                    \
+    delete u_.p;                                                                                                                   \
+    break
+    DEINIT(string_);
+    DEINIT(array_);
+    DEINIT(object_);
+#undef DEINIT
+  default:
+    break;
+  }
+}
+
+inline value::~value() {
+  clear();
+}
+
+inline value::value(const value &x) : type_(x.type_), u_() {
+  switch (type_) {
+#define INIT(p, v)                                                                                                                 \
+  case p##type:                                                                                                                    \
+    u_.p = v;                                                                                                                      \
+    break
+    INIT(string_, new std::string(*x.u_.string_));
+    INIT(array_, new array(*x.u_.array_));
+    INIT(object_, new object(*x.u_.object_));
+#undef INIT
+  default:
+    u_ = x.u_;
+    break;
+  }
+}
+
+inline value &value::operator=(const value &x) {
+  if (this != &x) {
+    value t(x);
+    swap(t);
+  }
+  return *this;
+}
+
+#if PICOJSON_USE_RVALUE_REFERENCE
+inline value::value(value &&x) PICOJSON_NOEXCEPT : type_(null_type), u_() {
+  swap(x);
+}
+inline value &value::operator=(value &&x) PICOJSON_NOEXCEPT {
+  swap(x);
+  return *this;
+}
+#endif
+inline void value::swap(value &x) PICOJSON_NOEXCEPT {
+  std::swap(type_, x.type_);
+  std::swap(u_, x.u_);
+}
+
+#define IS(ctype, jtype)                                                                                                           \
+  template <> inline bool value::is<ctype>() const {                                                                               \
+    return type_ == jtype##_type;                                                                                                  \
+  }
+IS(null, null)
+IS(bool, boolean)
+#ifdef PICOJSON_USE_INT64
+IS(int64_t, int64)
+#endif
+IS(std::string, string)
+IS(array, array)
+IS(object, object)
+#undef IS
+template <> inline bool value::is<double>() const {
+  return type_ == number_type
+#ifdef PICOJSON_USE_INT64
+         || type_ == int64_type
+#endif
+      ;
+}
+
+#define GET(ctype, var)                                                                                                            \
+  template <> inline const ctype &value::get<ctype>() const {                                                                      \
+    PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()" && is<ctype>());                                           \
+    return var;                                                                                                                    \
+  }                                                                                                                                \
+  template <> inline ctype &value::get<ctype>() {                                                                                  \
+    PICOJSON_ASSERT("type mismatch! call is<type>() before get<type>()" && is<ctype>());                                           \
+    return var;                                                                                                                    \
+  }
+GET(bool, u_.boolean_)
+GET(std::string, *u_.string_)
+GET(array, *u_.array_)
+GET(object, *u_.object_)
+#ifdef PICOJSON_USE_INT64
+GET(double,
+    (type_ == int64_type && (const_cast<value *>(this)->type_ = number_type, (const_cast<value *>(this)->u_.number_ = u_.int64_)),
+     u_.number_))
+GET(int64_t, u_.int64_)
+#else
+GET(double, u_.number_)
+#endif
+#undef GET
+
+#define SET(ctype, jtype, setter)                                                                                                  \
+  template <> inline void value::set<ctype>(const ctype &_val) {                                                                   \
+    clear();                                                                                                                       \
+    type_ = jtype##_type;                                                                                                          \
+    setter                                                                                                                         \
+  }
+SET(bool, boolean, u_.boolean_ = _val;)
+SET(std::string, string, u_.string_ = new std::string(_val);)
+SET(array, array, u_.array_ = new array(_val);)
+SET(object, object, u_.object_ = new object(_val);)
+SET(double, number, u_.number_ = _val;)
+#ifdef PICOJSON_USE_INT64
+SET(int64_t, int64, u_.int64_ = _val;)
+#endif
+#undef SET
+
+#if PICOJSON_USE_RVALUE_REFERENCE
+#define MOVESET(ctype, jtype, setter)                                                                                              \
+  template <> inline void value::set<ctype>(ctype && _val) {                                                                       \
+    clear();                                                                                                                       \
+    type_ = jtype##_type;                                                                                                          \
+    setter                                                                                                                         \
+  }
+MOVESET(std::string, string, u_.string_ = new std::string(std::move(_val));)
+MOVESET(array, array, u_.array_ = new array(std::move(_val));)
+MOVESET(object, object, u_.object_ = new object(std::move(_val));)
+#undef MOVESET
+#endif
+
+inline bool value::evaluate_as_boolean() const {
+  switch (type_) {
+  case null_type:
+    return false;
+  case boolean_type:
+    return u_.boolean_;
+  case number_type:
+    return u_.number_ != 0;
+#ifdef PICOJSON_USE_INT64
+  case int64_type:
+    return u_.int64_ != 0;
+#endif
+  case string_type:
+    return !u_.string_->empty();
+  default:
+    return true;
+  }
+}
+
+inline const value &value::get(const size_t idx) const {
+  static value s_null;
+  PICOJSON_ASSERT(is<array>());
+  return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;
+}
+
+inline value &value::get(const size_t idx) {
+  static value s_null;
+  PICOJSON_ASSERT(is<array>());
+  return idx < u_.array_->size() ? (*u_.array_)[idx] : s_null;
+}
+
+inline const value &value::get(const std::string &key) const {
+  static value s_null;
+  PICOJSON_ASSERT(is<object>());
+  object::const_iterator i = u_.object_->find(key);
+  return i != u_.object_->end() ? i->second : s_null;
+}
+
+inline value &value::get(const std::string &key) {
+  static value s_null;
+  PICOJSON_ASSERT(is<object>());
+  object::iterator i = u_.object_->find(key);
+  return i != u_.object_->end() ? i->second : s_null;
+}
+
+inline bool value::contains(const size_t idx) const {
+  PICOJSON_ASSERT(is<array>());
+  return idx < u_.array_->size();
+}
+
+inline bool value::contains(const std::string &key) const {
+  PICOJSON_ASSERT(is<object>());
+  object::const_iterator i = u_.object_->find(key);
+  return i != u_.object_->end();
+}
+
+inline std::string value::to_str() const {
+  switch (type_) {
+  case null_type:
+    return "null";
+  case boolean_type:
+    return u_.boolean_ ? "true" : "false";
+#ifdef PICOJSON_USE_INT64
+  case int64_type: {
+    char buf[sizeof("-9223372036854775808")];
+    SNPRINTF(buf, sizeof(buf), "%" PRId64, u_.int64_);
+    return buf;
+  }
+#endif
+  case number_type: {
+    char buf[256];
+    double tmp;
+    SNPRINTF(buf, sizeof(buf), fabs(u_.number_) < (1ULL << 53) && modf(u_.number_, &tmp) == 0 ? "%.f" : "%.17g", u_.number_);
+#if PICOJSON_USE_LOCALE
+    char *decimal_point = localeconv()->decimal_point;
+    if (strcmp(decimal_point, ".") != 0) {
+      size_t decimal_point_len = strlen(decimal_point);
+      for (char *p = buf; *p != '\0'; ++p) {
+        if (strncmp(p, decimal_point, decimal_point_len) == 0) {
+          return std::string(buf, p) + "." + (p + decimal_point_len);
+        }
+      }
+    }
+#endif
+    return buf;
+  }
+  case string_type:
+    return *u_.string_;
+  case array_type:
+    return "array";
+  case object_type:
+    return "object";
+  default:
+    PICOJSON_ASSERT(0);
+#ifdef _MSC_VER
+    __assume(0);
+#endif
+  }
+  return std::string();
+}
+
+template <typename Iter> void copy(const std::string &s, Iter oi) {
+  std::copy(s.begin(), s.end(), oi);
+}
+
+template <typename Iter> struct serialize_str_char {
+  Iter oi;
+  void operator()(char c) {
+    switch (c) {
+#define MAP(val, sym)                                                                                                              \
+  case val:                                                                                                                        \
+    copy(sym, oi);                                                                                                                 \
+    break
+      MAP('"', "\\\"");
+      MAP('\\', "\\\\");
+      MAP('/', "\\/");
+      MAP('\b', "\\b");
+      MAP('\f', "\\f");
+      MAP('\n', "\\n");
+      MAP('\r', "\\r");
+      MAP('\t', "\\t");
+#undef MAP
+    default:
+      if (static_cast<unsigned char>(c) < 0x20 || c == 0x7f) {
+        char buf[7];
+        SNPRINTF(buf, sizeof(buf), "\\u%04x", c & 0xff);
+        copy(buf, buf + 6, oi);
+      } else {
+        *oi++ = c;
+      }
+      break;
+    }
+  }
+};
+
+template <typename Iter> void serialize_str(const std::string &s, Iter oi) {
+  *oi++ = '"';
+  serialize_str_char<Iter> process_char = {oi};
+  std::for_each(s.begin(), s.end(), process_char);
+  *oi++ = '"';
+}
+
+template <typename Iter> void value::serialize(Iter oi, bool prettify) const {
+  return _serialize(oi, prettify ? 0 : -1);
+}
+
+inline std::string value::serialize(bool prettify) const {
+  return _serialize(prettify ? 0 : -1);
+}
+
+template <typename Iter> void value::_indent(Iter oi, int indent) {
+  *oi++ = '\n';
+  for (int i = 0; i < indent * INDENT_WIDTH; ++i) {
+    *oi++ = ' ';
+  }
+}
+
+template <typename Iter> void value::_serialize(Iter oi, int indent) const {
+  switch (type_) {
+  case string_type:
+    serialize_str(*u_.string_, oi);
+    break;
+  case array_type: {
+    *oi++ = '[';
+    if (indent != -1) {
+      ++indent;
+    }
+    for (array::const_iterator i = u_.array_->begin(); i != u_.array_->end(); ++i) {
+      if (i != u_.array_->begin()) {
+        *oi++ = ',';
+      }
+      if (indent != -1) {
+        _indent(oi, indent);
+      }
+      i->_serialize(oi, indent);
+    }
+    if (indent != -1) {
+      --indent;
+      if (!u_.array_->empty()) {
+        _indent(oi, indent);
+      }
+    }
+    *oi++ = ']';
+    break;
+  }
+  case object_type: {
+    *oi++ = '{';
+    if (indent != -1) {
+      ++indent;
+    }
+    for (object::const_iterator i = u_.object_->begin(); i != u_.object_->end(); ++i) {
+      if (i != u_.object_->begin()) {
+        *oi++ = ',';
+      }
+      if (indent != -1) {
+        _indent(oi, indent);
+      }
+      serialize_str(i->first, oi);
+      *oi++ = ':';
+      if (indent != -1) {
+        *oi++ = ' ';
+      }
+      i->second._serialize(oi, indent);
+    }
+    if (indent != -1) {
+      --indent;
+      if (!u_.object_->empty()) {
+        _indent(oi, indent);
+      }
+    }
+    *oi++ = '}';
+    break;
+  }
+  default:
+    copy(to_str(), oi);
+    break;
+  }
+  if (indent == 0) {
+    *oi++ = '\n';
+  }
+}
+
+inline std::string value::_serialize(int indent) const {
+  std::string s;
+  _serialize(std::back_inserter(s), indent);
+  return s;
+}
+
+template <typename Iter> class input {
+protected:
+  Iter cur_, end_;
+  bool consumed_;
+  int line_;
+
+public:
+  input(const Iter &first, const Iter &last) : cur_(first), end_(last), consumed_(false), line_(1) {
+  }
+  int getc() {
+    if (consumed_) {
+      if (*cur_ == '\n') {
+        ++line_;
+      }
+      ++cur_;
+    }
+    if (cur_ == end_) {
+      consumed_ = false;
+      return -1;
+    }
+    consumed_ = true;
+    return *cur_ & 0xff;
+  }
+  void ungetc() {
+    consumed_ = false;
+  }
+  Iter cur() const {
+    if (consumed_) {
+      input<Iter> *self = const_cast<input<Iter> *>(this);
+      self->consumed_ = false;
+      ++self->cur_;
+    }
+    return cur_;
+  }
+  int line() const {
+    return line_;
+  }
+  void skip_ws() {
+    while (1) {
+      int ch = getc();
+      if (!(ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')) {
+        ungetc();
+        break;
+      }
+    }
+  }
+  bool expect(const int expected) {
+    skip_ws();
+    if (getc() != expected) {
+      ungetc();
+      return false;
+    }
+    return true;
+  }
+  bool match(const std::string &pattern) {
+    for (std::string::const_iterator pi(pattern.begin()); pi != pattern.end(); ++pi) {
+      if (getc() != *pi) {
+        ungetc();
+        return false;
+      }
+    }
+    return true;
+  }
+};
+
+template <typename Iter> inline int _parse_quadhex(input<Iter> &in) {
+  int uni_ch = 0, hex;
+  for (int i = 0; i < 4; i++) {
+    if ((hex = in.getc()) == -1) {
+      return -1;
+    }
+    if ('0' <= hex && hex <= '9') {
+      hex -= '0';
+    } else if ('A' <= hex && hex <= 'F') {
+      hex -= 'A' - 0xa;
+    } else if ('a' <= hex && hex <= 'f') {
+      hex -= 'a' - 0xa;
+    } else {
+      in.ungetc();
+      return -1;
+    }
+    uni_ch = uni_ch * 16 + hex;
+  }
+  return uni_ch;
+}
+
+template <typename String, typename Iter> inline bool _parse_codepoint(String &out, input<Iter> &in) {
+  int uni_ch;
+  if ((uni_ch = _parse_quadhex(in)) == -1) {
+    return false;
+  }
+  if (0xd800 <= uni_ch && uni_ch <= 0xdfff) {
+    if (0xdc00 <= uni_ch) {
+      // a second 16-bit of a surrogate pair appeared
+      return false;
+    }
+    // first 16-bit of surrogate pair, get the next one
+    if (in.getc() != '\\' || in.getc() != 'u') {
+      in.ungetc();
+      return false;
+    }
+    int second = _parse_quadhex(in);
+    if (!(0xdc00 <= second && second <= 0xdfff)) {
+      return false;
+    }
+    uni_ch = ((uni_ch - 0xd800) << 10) | ((second - 0xdc00) & 0x3ff);
+    uni_ch += 0x10000;
+  }
+  if (uni_ch < 0x80) {
+    out.push_back(static_cast<char>(uni_ch));
+  } else {
+    if (uni_ch < 0x800) {
+      out.push_back(static_cast<char>(0xc0 | (uni_ch >> 6)));
+    } else {
+      if (uni_ch < 0x10000) {
+        out.push_back(static_cast<char>(0xe0 | (uni_ch >> 12)));
+      } else {
+        out.push_back(static_cast<char>(0xf0 | (uni_ch >> 18)));
+        out.push_back(static_cast<char>(0x80 | ((uni_ch >> 12) & 0x3f)));
+      }
+      out.push_back(static_cast<char>(0x80 | ((uni_ch >> 6) & 0x3f)));
+    }
+    out.push_back(static_cast<char>(0x80 | (uni_ch & 0x3f)));
+  }
+  return true;
+}
+
+template <typename String, typename Iter> inline bool _parse_string(String &out, input<Iter> &in) {
+  while (1) {
+    int ch = in.getc();
+    if (ch < ' ') {
+      in.ungetc();
+      return false;
+    } else if (ch == '"') {
+      return true;
+    } else if (ch == '\\') {
+      if ((ch = in.getc()) == -1) {
+        return false;
+      }
+      switch (ch) {
+#define MAP(sym, val)                                                                                                              \
+  case sym:                                                                                                                        \
+    out.push_back(val);                                                                                                            \
+    break
+        MAP('"', '\"');
+        MAP('\\', '\\');
+        MAP('/', '/');
+        MAP('b', '\b');
+        MAP('f', '\f');
+        MAP('n', '\n');
+        MAP('r', '\r');
+        MAP('t', '\t');
+#undef MAP
+      case 'u':
+        if (!_parse_codepoint(out, in)) {
+          return false;
+        }
+        break;
+      default:
+        return false;
+      }
+    } else {
+      out.push_back(static_cast<char>(ch));
+    }
+  }
+  return false;
+}
+
+template <typename Context, typename Iter> inline bool _parse_array(Context &ctx, input<Iter> &in) {
+  if (!ctx.parse_array_start()) {
+    return false;
+  }
+  size_t idx = 0;
+  if (in.expect(']')) {
+    return ctx.parse_array_stop(idx);
+  }
+  do {
+    if (!ctx.parse_array_item(in, idx)) {
+      return false;
+    }
+    idx++;
+  } while (in.expect(','));
+  return in.expect(']') && ctx.parse_array_stop(idx);
+}
+
+template <typename Context, typename Iter> inline bool _parse_object(Context &ctx, input<Iter> &in) {
+  if (!ctx.parse_object_start()) {
+    return false;
+  }
+  if (in.expect('}')) {
+    return ctx.parse_object_stop();
+  }
+  do {
+    std::string key;
+    if (!in.expect('"') || !_parse_string(key, in) || !in.expect(':')) {
+      return false;
+    }
+    if (!ctx.parse_object_item(in, key)) {
+      return false;
+    }
+  } while (in.expect(','));
+  return in.expect('}') && ctx.parse_object_stop();
+}
+
+template <typename Iter> inline std::string _parse_number(input<Iter> &in) {
+  std::string num_str;
+  while (1) {
+    int ch = in.getc();
+    if (('0' <= ch && ch <= '9') || ch == '+' || ch == '-' || ch == 'e' || ch == 'E') {
+      num_str.push_back(static_cast<char>(ch));
+    } else if (ch == '.') {
+#if PICOJSON_USE_LOCALE
+      num_str += localeconv()->decimal_point;
+#else
+      num_str.push_back('.');
+#endif
+    } else {
+      in.ungetc();
+      break;
+    }
+  }
+  return num_str;
+}
+
+template <typename Context, typename Iter> inline bool _parse(Context &ctx, input<Iter> &in) {
+  in.skip_ws();
+  int ch = in.getc();
+  switch (ch) {
+#define IS(ch, text, op)                                                                                                           \
+  case ch:                                                                                                                         \
+    if (in.match(text) && op) {                                                                                                    \
+      return true;                                                                                                                 \
+    } else {                                                                                                                       \
+      return false;                                                                                                                \
+    }
+    IS('n', "ull", ctx.set_null());
+    IS('f', "alse", ctx.set_bool(false));
+    IS('t', "rue", ctx.set_bool(true));
+#undef IS
+  case '"':
+    return ctx.parse_string(in);
+  case '[':
+    return _parse_array(ctx, in);
+  case '{':
+    return _parse_object(ctx, in);
+  default:
+    if (('0' <= ch && ch <= '9') || ch == '-') {
+      double f;
+      char *endp;
+      in.ungetc();
+      std::string num_str(_parse_number(in));
+      if (num_str.empty()) {
+        return false;
+      }
+#ifdef PICOJSON_USE_INT64
+      {
+        errno = 0;
+        intmax_t ival = strtoimax(num_str.c_str(), &endp, 10);
+        if (errno == 0 && std::numeric_limits<int64_t>::min() <= ival && ival <= std::numeric_limits<int64_t>::max() &&
+            endp == num_str.c_str() + num_str.size()) {
+          ctx.set_int64(ival);
+          return true;
+        }
+      }
+#endif
+      f = strtod(num_str.c_str(), &endp);
+      if (endp == num_str.c_str() + num_str.size()) {
+        ctx.set_number(f);
+        return true;
+      }
+      return false;
+    }
+    break;
+  }
+  in.ungetc();
+  return false;
+}
+
+class deny_parse_context {
+public:
+  bool set_null() {
+    return false;
+  }
+  bool set_bool(bool) {
+    return false;
+  }
+#ifdef PICOJSON_USE_INT64
+  bool set_int64(int64_t) {
+    return false;
+  }
+#endif
+  bool set_number(double) {
+    return false;
+  }
+  template <typename Iter> bool parse_string(input<Iter> &) {
+    return false;
+  }
+  bool parse_array_start() {
+    return false;
+  }
+  template <typename Iter> bool parse_array_item(input<Iter> &, size_t) {
+    return false;
+  }
+  bool parse_array_stop(size_t) {
+    return false;
+  }
+  bool parse_object_start() {
+    return false;
+  }
+  template <typename Iter> bool parse_object_item(input<Iter> &, const std::string &) {
+    return false;
+  }
+};
+
+class default_parse_context {
+protected:
+  value *out_;
+  size_t depths_;
+
+public:
+  default_parse_context(value *out, size_t depths = DEFAULT_MAX_DEPTHS) : out_(out), depths_(depths) {
+  }
+  bool set_null() {
+    *out_ = value();
+    return true;
+  }
+  bool set_bool(bool b) {
+    *out_ = value(b);
+    return true;
+  }
+#ifdef PICOJSON_USE_INT64
+  bool set_int64(int64_t i) {
+    *out_ = value(i);
+    return true;
+  }
+#endif
+  bool set_number(double f) {
+    *out_ = value(f);
+    return true;
+  }
+  template <typename Iter> bool parse_string(input<Iter> &in) {
+    *out_ = value(string_type, false);
+    return _parse_string(out_->get<std::string>(), in);
+  }
+  bool parse_array_start() {
+    if (depths_ == 0)
+      return false;
+    --depths_;
+    *out_ = value(array_type, false);
+    return true;
+  }
+  template <typename Iter> bool parse_array_item(input<Iter> &in, size_t) {
+    array &a = out_->get<array>();
+    a.push_back(value());
+    default_parse_context ctx(&a.back(), depths_);
+    return _parse(ctx, in);
+  }
+  bool parse_array_stop(size_t) {
+    ++depths_;
+    return true;
+  }
+  bool parse_object_start() {
+    if (depths_ == 0)
+      return false;
+    *out_ = value(object_type, false);
+    return true;
+  }
+  template <typename Iter> bool parse_object_item(input<Iter> &in, const std::string &key) {
+    object &o = out_->get<object>();
+    default_parse_context ctx(&o[key], depths_);
+    return _parse(ctx, in);
+  }
+  bool parse_object_stop() {
+    ++depths_;
+    return true;
+  }
+
+private:
+  default_parse_context(const default_parse_context &);
+  default_parse_context &operator=(const default_parse_context &);
+};
+
+class null_parse_context {
+protected:
+  size_t depths_;
+
+public:
+  struct dummy_str {
+    void push_back(int) {
+    }
+  };
+
+public:
+  null_parse_context(size_t depths = DEFAULT_MAX_DEPTHS) : depths_(depths) {
+  }
+  bool set_null() {
+    return true;
+  }
+  bool set_bool(bool) {
+    return true;
+  }
+#ifdef PICOJSON_USE_INT64
+  bool set_int64(int64_t) {
+    return true;
+  }
+#endif
+  bool set_number(double) {
+    return true;
+  }
+  template <typename Iter> bool parse_string(input<Iter> &in) {
+    dummy_str s;
+    return _parse_string(s, in);
+  }
+  bool parse_array_start() {
+    if (depths_ == 0)
+      return false;
+    --depths_;
+    return true;
+  }
+  template <typename Iter> bool parse_array_item(input<Iter> &in, size_t) {
+    return _parse(*this, in);
+  }
+  bool parse_array_stop(size_t) {
+    ++depths_;
+    return true;
+  }
+  bool parse_object_start() {
+    if (depths_ == 0)
+      return false;
+    --depths_;
+    return true;
+  }
+  template <typename Iter> bool parse_object_item(input<Iter> &in, const std::string &) {
+    ++depths_;
+    return _parse(*this, in);
+  }
+  bool parse_object_stop() {
+    return true;
+  }
+
+private:
+  null_parse_context(const null_parse_context &);
+  null_parse_context &operator=(const null_parse_context &);
+};
+
+// obsolete, use the version below
+template <typename Iter> inline std::string parse(value &out, Iter &pos, const Iter &last) {
+  std::string err;
+  pos = parse(out, pos, last, &err);
+  return err;
+}
+
+template <typename Context, typename Iter> inline Iter _parse(Context &ctx, const Iter &first, const Iter &last, std::string *err) {
+  input<Iter> in(first, last);
+  if (!_parse(ctx, in) && err != NULL) {
+    char buf[64];
+    SNPRINTF(buf, sizeof(buf), "syntax error at line %d near: ", in.line());
+    *err = buf;
+    while (1) {
+      int ch = in.getc();
+      if (ch == -1 || ch == '\n') {
+        break;
+      } else if (ch >= ' ') {
+        err->push_back(static_cast<char>(ch));
+      }
+    }
+  }
+  return in.cur();
+}
+
+template <typename Iter> inline Iter parse(value &out, const Iter &first, const Iter &last, std::string *err) {
+  default_parse_context ctx(&out);
+  return _parse(ctx, first, last, err);
+}
+
+inline std::string parse(value &out, const std::string &s) {
+  std::string err;
+  parse(out, s.begin(), s.end(), &err);
+  return err;
+}
+
+inline std::string parse(value &out, std::istream &is) {
+  std::string err;
+  parse(out, std::istreambuf_iterator<char>(is.rdbuf()), std::istreambuf_iterator<char>(), &err);
+  return err;
+}
+
+template <typename T> struct last_error_t { static std::string s; };
+template <typename T> std::string last_error_t<T>::s;
+
+inline void set_last_error(const std::string &s) {
+  last_error_t<bool>::s = s;
+}
+
+inline const std::string &get_last_error() {
+  return last_error_t<bool>::s;
+}
+
+inline bool operator==(const value &x, const value &y) {
+  if (x.is<null>())
+    return y.is<null>();
+#define PICOJSON_CMP(type)                                                                                                         \
+  if (x.is<type>())                                                                                                                \
+  return y.is<type>() && x.get<type>() == y.get<type>()
+  PICOJSON_CMP(bool);
+  PICOJSON_CMP(double);
+  PICOJSON_CMP(std::string);
+  PICOJSON_CMP(array);
+  PICOJSON_CMP(object);
+#undef PICOJSON_CMP
+  PICOJSON_ASSERT(0);
+#ifdef _MSC_VER
+  __assume(0);
+#endif
+  return false;
+}
+
+inline bool operator!=(const value &x, const value &y) {
+  return !(x == y);
+}
+}
+
+#if !PICOJSON_USE_RVALUE_REFERENCE
+namespace std {
+template <> inline void swap(picojson::value &x, picojson::value &y) {
+  x.swap(y);
+}
+}
+#endif
+
+inline std::istream &operator>>(std::istream &is, picojson::value &x) {
+  picojson::set_last_error(std::string());
+  const std::string err(picojson::parse(x, is));
+  if (!err.empty()) {
+    picojson::set_last_error(err);
+    is.setstate(std::ios::failbit);
+  }
+  return is;
+}
+
+inline std::ostream &operator<<(std::ostream &os, const picojson::value &x) {
+  x.serialize(std::ostream_iterator<char>(os));
+  return os;
+}
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif

+ 1 - 1
frameworks/C++/cutelyst/src/singledatabasequerytest.cpp

@@ -22,7 +22,7 @@ void SingleDatabaseQueryTest::dbp(Context *c)
 
 
     ASync async(c);
     ASync async(c);
     static thread_local auto db = APool::database();
     static thread_local auto db = APool::database();
-    db.execPrepared(APreparedQueryLiteral("SELECT id, randomNumber FROM world WHERE id=$1"),
+    db.exec(APreparedQueryLiteral(u"SELECT id, randomNumber FROM world WHERE id=$1"),
                            {id}, [c, async] (AResult &result) {
                            {id}, [c, async] (AResult &result) {
         if (Q_LIKELY(!result.error() && result.size())) {
         if (Q_LIKELY(!result.error() && result.size())) {
             auto it = result.begin();
             auto it = result.begin();