jsoncons es una biblioteca C++ de solo encabezado para construir formatos de datos JSON y similares a JSON, como CBOR. Para cada formato de datos admitido, le permite trabajar con los datos de varias maneras:
Como estructura de datos similar a una variante y que reconoce el asignador, basic_json
Como una estructura de datos C++ fuertemente tipada que implementa json_type_traits
Con acceso a nivel de cursor a un flujo de eventos de análisis, algo análogo al análisis de extracción StAX y la serialización push en el mundo XML.
En comparación con otras bibliotecas JSON, jsoncons ha sido diseñada para manejar textos JSON muy grandes. En esencia, se encuentran los analizadores y serializadores estilo SAX. Admite la lectura de un texto JSON completo en la memoria en una estructura similar a una variante. Pero también admite el acceso eficiente a los datos subyacentes mediante el análisis de extracción y la serialización push estilo StAX. Y admite el análisis incremental en la forma preferida de un usuario, utilizando información sobre los tipos de usuarios proporcionada por las especializaciones de json_type_traits.
El modelo de datos jsoncons admite los tipos JSON familiares (nulos, booleanos, números, cadenas, matrices, objetos) además de cadenas de bytes. Además, jsoncons admite el etiquetado semántico de fechas y épocas, números enteros grandes, decimales grandes, flotantes grandes y codificaciones binarias. Esto le permite preservar esta semántica de tipos al analizar formatos de datos similares a JSON, como CBOR, que los tienen.
jsoncons se distribuye bajo la licencia de software Boost.
jsoncons es gratuito pero agradece el apoyo para sostener su desarrollo. Si encuentra útil esta biblioteca, considere hacer una donación única o convertirse en patrocinador ❤️.
A medida que la biblioteca jsoncons
ha ido evolucionando, en ocasiones los nombres han cambiado. Para facilitar la transición, jsoncons desaprueba los nombres antiguos pero continúa admitiendo muchos de ellos. Los nombres obsoletos se pueden suprimir definiendo la macro JSONCONS_NO_DEPRECATED
, y se recomienda hacerlo para el código nuevo.
"Apache Kvrocks utiliza constantemente jsoncons para ofrecer soporte para estructuras de datos JSON a los usuarios. ¡Consideramos que la experiencia de desarrollo con jsoncons es excepcional!"
"He estado usando su biblioteca en mi idioma nativo, R, y he creado un paquete R que facilita (a) las consultas JMESpath y JSONpath en cadenas JSON u objetos R y (b) para que otros desarrolladores de R se vinculen a su biblioteca. ".
"Estoy usando su biblioteca como interfaz externa para pasar datos, además de usar las conversiones de csv a json, que son realmente útiles para convertir datos para usar en javascript"
"Verificado que, para mis necesidades en JSON y CBOR, está funcionando perfectamente"
"La característica JSONPath de esta biblioteca es genial"
"Utilizamos la implementación JMESPath bastante"
"Nos encanta su validador de esquemas JSON. Lo estamos usando en ER/Studio, nuestra herramienta de modelado de datos, para analizar archivos de esquemas JSON y poder crear modelos de relaciones entre entidades a partir de ellos".
"la biblioteca de serialización preferida con sus hermosas asignaciones y facilidad de uso"
"realmente bueno" "proyecto increíble" "muy sólido y muy confiable" "a mi equipo le encanta" "¡¡¡Tu repositorio es genial!!!!!"
Comience a utilizar conjuntos de imágenes y marcos de imágenes de HealthImaging mediante un SDK de AWS
RubyGems.org rjsoncons Coppelia Robotics Licencias CSPro
Puede utilizar el administrador de bibliotecas de la plataforma vcpkg para instalar el paquete jsoncons.
O descargue la última versión y descomprima el archivo zip. Copie el directorio include/jsoncons
a su directorio include
. Si desea utilizar extensiones, copie también include/jsoncons_ext
.
O descargue el código más reciente en main.
La biblioteca requiere un compilador de C++ compatible con C++11. Además, la biblioteca define jsoncons::endian
, jsoncons::basic_string_view
, jsoncons::optional
y jsoncons::span
, que se escribirán según sus equivalentes de biblioteca estándar si se detectan. De lo contrario, se escribirán en implementaciones internas compatibles con C++11.
La biblioteca utiliza excepciones y, en algunos casos, std::error_code para informar errores. Aparte de jsoncons::assertion_error
, todas las clases de excepción de jsoncons implementan la interfaz jsoncons::json_error. Si las excepciones están deshabilitadas o si se define la macro de tiempo de compilación JSONCONS_NO_EXCEPTIONS
, los lanzamientos se convierten en llamadas a std::terminate
.
json_benchmarks proporciona algunas medidas sobre cómo se compara jsoncons
con otras bibliotecas json
.
Conjuntos de pruebas JSONTestSuite y JSON_checker
Comparativas de rendimiento con texto y números enteros
Puntos de referencia de rendimiento con texto y dobles.
La comparación de JSONPath muestra cómo jsoncons JsonPath se compara con otras implementaciones
Trabajar con datos JSON
Trabajar con datos CBOR
Para los ejemplos siguientes, debe incluir algunos archivos de encabezado e inicializar una cadena de datos JSON:
# include < jsoncons/json.hpp >
# include < jsoncons_ext/jsonpath/jsonpath.hpp >
# include < iostream >
using namespace jsoncons ; // for convenience
std::string data = R"(
{
"application": "hiking",
"reputons": [
{
"rater": "HikingAsylum",
"assertion": "advanced",
"rated": "Marilyn C",
"rating": 0.90,
"generated": 1514862245
}
]
}
)" ;
jsoncons le permite trabajar con los datos de varias maneras:
Como estructura de datos tipo variante, basic_json
Como una estructura de datos C++ fuertemente tipada que implementa json_type_traits
Con acceso a nivel de cursor a un flujo de eventos de análisis
int main ()
{
// Parse the string of data into a json value
json j = json::parse (data);
// Does object member reputons exist?
std::cout << " (1) " << std::boolalpha << j. contains ( " reputons " ) << " nn " ;
// Get a reference to reputons array
const json& v = j[ " reputons " ];
// Iterate over reputons array
std::cout << " (2) n " ;
for ( const auto & item : v. array_range ())
{
// Access rated as string and rating as double
std::cout << item[ " rated " ]. as <std::string>() << " , " << item[ " rating " ]. as < double >() << " n " ;
}
std::cout << " n " ;
// Select all "rated" with JSONPath
std::cout << " (3) n " ;
json result = jsonpath::json_query (j, " $..rated " );
std::cout << pretty_print (result) << " nn " ;
// Serialize back to JSON
std::cout << " (4) n " << pretty_print (j) << " nn " ;
}
Producción:
(1) true
(2)
Marilyn C, 0.9
(3)
[
"Marilyn C"
]
(4)
{
"application": "hiking",
"reputons": [
{
"assertion": "advanced",
"generated": 1514862245,
"rated": "Marilyn C",
"rater": "HikingAsylum",
"rating": 0.9
}
]
}
jsoncons admite la transformación de textos JSON en estructuras de datos C++. Las funciones decode_json y encode_json convierten cadenas o flujos de datos JSON en estructuras de datos C++ y viceversa. Decodifica y codifica el trabajo para todas las clases de C++ que tienen json_type_traits definidos. jsoncons ya admite muchos tipos en la biblioteca estándar, y sus propios tipos también serán compatibles si especializa json_type_traits
en el espacio de nombres jsoncons
.
namespace ns {
enum class hiking_experience {beginner,intermediate,advanced};
class hiking_reputon
{
std::string rater_;
hiking_experience assertion_;
std::string rated_;
double rating_;
std::optional<std::chrono::seconds> generated_; // assumes C++17, if not use jsoncons::optional
std::optional<std::chrono::seconds> expires_;
public:
hiking_reputon ( const std::string& rater,
hiking_experience assertion,
const std::string& rated,
double rating,
const std::optional<std::chrono::seconds>& generated =
std::optional<std::chrono::seconds>(),
const std::optional<std::chrono::seconds>& expires =
std::optional<std::chrono::seconds>())
: rater_(rater), assertion_(assertion), rated_(rated), rating_(rating),
generated_ (generated), expires_(expires)
{
}
const std::string& rater () const { return rater_;}
hiking_experience assertion () const { return assertion_;}
const std::string& rated () const { return rated_;}
double rating () const { return rating_;}
std::optional<std::chrono::seconds> generated () const { return generated_;}
std::optional<std::chrono::seconds> expires () const { return expires_;}
friend bool operator ==( const hiking_reputon& lhs, const hiking_reputon& rhs)
{
return lhs. rater_ == rhs. rater_ && lhs. assertion_ == rhs. assertion_ &&
lhs. rated_ == rhs. rated_ && lhs. rating_ == rhs. rating_ &&
lhs. confidence_ == rhs. confidence_ && lhs. expires_ == rhs. expires_ ;
}
friend bool operator !=( const hiking_reputon& lhs, const hiking_reputon& rhs)
{
return !(lhs == rhs);
};
};
class hiking_reputation
{
std::string application_;
std::vector<hiking_reputon> reputons_;
public:
hiking_reputation ( const std::string& application,
const std::vector<hiking_reputon>& reputons)
: application_(application),
reputons_ (reputons)
{}
const std::string& application () const { return application_;}
const std::vector<hiking_reputon>& reputons () const { return reputons_;}
};
} // namespace ns
// Declare the traits. Specify which data members need to be serialized.
JSONCONS_ENUM_TRAITS (ns::hiking_experience, beginner, intermediate, advanced)
// First four members listed are mandatory, generated and expires are optional
JSONCONS_N_CTOR_GETTER_TRAITS(ns::hiking_reputon, 4 , rater, assertion, rated, rating,
generated, expires)
// All members are mandatory
JSONCONS_ALL_CTOR_GETTER_TRAITS(ns::hiking_reputation, application, reputons)
int main()
{
// Decode the string of data into a c++ structure
ns::hiking_reputation v = decode_json<ns::hiking_reputation>(data);
// Iterate over reputons array value
std::cout << " (1) n " ;
for ( const auto & item : v. reputons ())
{
std::cout << item. rated () << " , " << item. rating ();
if (item. generated ())
{
std::cout << " , " << (*item. generated ()). count ();
}
std::cout << " n " ;
}
// Encode the c++ structure into a string
std::string s;
encode_json (v, s, indenting::indent);
std::cout << " (2) n " ;
std::cout << s << " n " ;
}
Producción:
(1)
Marilyn C, 0.9, 1514862245
(2)
{
"application": "hiking",
"reputons": [
{
"assertion": "advanced",
"generated": 1514862245,
"rated": "Marilyn C",
"rater": "HikingAsylum",
"rating": 0.9
}
]
}
Este ejemplo utiliza las macros de conveniencia JSONCONS_ENUM_TRAITS
, JSONCONS_N_CTOR_GETTER_TRAITS
y JSONCONS_ALL_CTOR_GETTER_TRAITS
para especializar json_type_traits para el tipo de enumeración ns::hiking_experience
, la clase ns::hiking_reputon
(con algunos miembros no obligatorios) y la clase ns::hiking_reputation
(con todos los miembros obligatorios). La macro JSONCONS_ENUM_TRAITS
genera el código a partir de los identificadores de enumeración, y las macros JSONCONS_N_CTOR_GETTER_TRAITS
y JSONCONS_ALL_CTOR_GETTER_TRAITS
generan el código a partir de las funciones get y un constructor. Estas declaraciones de macro deben colocarse fuera de cualquier bloque de espacio de nombres.
Consulte ejemplos para conocer otras formas de especializar json_type_traits
.
Una aplicación típica de análisis pull procesará repetidamente el evento current()
y llamará next()
para avanzar al siguiente evento, hasta que done()
devuelva true
.
int main ()
{
json_string_cursor cursor (data);
for (; !cursor. done (); cursor. next ())
{
const auto & event = cursor. current ();
switch (event. event_type ())
{
case staj_event_type::begin_array:
std::cout << event. event_type () << " " << " n " ;
break ;
case staj_event_type::end_array:
std::cout << event. event_type () << " " << " n " ;
break ;
case staj_event_type::begin_object:
std::cout << event. event_type () << " " << " n " ;
break ;
case staj_event_type::end_object:
std::cout << event. event_type () << " " << " n " ;
break ;
case staj_event_type::key:
// Or std::string_view, if supported
std::cout << event. event_type () << " : " << event. get <jsoncons::string_view>() << " n " ;
break ;
case staj_event_type::string_value:
// Or std::string_view, if supported
std::cout << event. event_type () << " : " << event. get <jsoncons::string_view>() << " n " ;
break ;
case staj_event_type::null_value:
std::cout << event. event_type () << " n " ;
break ;
case staj_event_type::bool_value:
std::cout << event. event_type () << " : " << std::boolalpha << event. get < bool >() << " n " ;
break ;
case staj_event_type::int64_value:
std::cout << event. event_type () << " : " << event. get < int64_t >() << " n " ;
break ;
case staj_event_type::uint64_value:
std::cout << event. event_type () << " : " << event. get < uint64_t >() << " n " ;
break ;
case staj_event_type::double_value:
std::cout << event. event_type () << " : " << event. get < double >() << " n " ;
break ;
default :
std::cout << " Unhandled event type: " << event. event_type () << " " << " n " ;
break ;
}
}
}
Producción:
begin_object
key: application
string_value: hiking
key: reputons
begin_array
begin_object
key: rater
string_value: HikingAsylum
key: assertion
string_value: advanced
key: rated
string_value: Marilyn C
key: rating
double_value: 0.9
key: generated
uint64_value: 1514862245
end_object
end_array
end_object
Puede aplicar un filtro a un cursor usando la sintaxis de canalización (por ejemplo, cursor | filter1 | filter2 | ...
)
int main ()
{
std::string name;
auto filter = [&]( const staj_event& ev, const ser_context&) -> bool
{
if (ev. event_type () == staj_event_type::key)
{
name = ev. get <std::string>();
return false ;
}
if (name == " rated " )
{
name. clear ();
return true ;
}
return false ;
};
json_string_cursor cursor (data);
auto filtered_c = cursor | filter;
for (; !filtered_c. done (); filtered_c. next ())
{
const auto & event = filtered_c. current ();
switch (event. event_type ())
{
case staj_event_type::string_value:
// Or std::string_view, if C++17
std::cout << event. event_type () << " : " << event. get <jsoncons::string_view>() << " n " ;
break ;
default :
std::cout << " Unhandled event type n " ;
break ;
}
}
}
Producción:
Marilyn C
Para los ejemplos siguientes, debe incluir algunos archivos de encabezado e inicializar un búfer de datos CBOR:
# include < iomanip >
# include < iostream >
# include < jsoncons/json.hpp >
# include < jsoncons_ext/cbor/cbor.hpp >
# include < jsoncons_ext/jsonpath/jsonpath.hpp >
using namespace jsoncons ; // for convenience
const std::vector< uint8_t > data = {
0x9f , // Start indefinte length array
0x83 , // Array of length 3
0x63 , // String value of length 3
0x66 , 0x6f , 0x6f , // "foo"
0x44 , // Byte string value of length 4
0x50 , 0x75 , 0x73 , 0x73 , // 'P''u''s''s'
0xc5 , // Tag 5 (bigfloat)
0x82 , // Array of length 2
0x20 , // -1
0x03 , // 3
0x83 , // Another array of length 3
0x63 , // String value of length 3
0x62 , 0x61 , 0x72 , // "bar"
0xd6 , // Expected conversion to base64
0x44 , // Byte string value of length 4
0x50 , 0x75 , 0x73 , 0x73 , // 'P''u''s''s'
0xc4 , // Tag 4 (decimal fraction)
0x82 , // Array of length 2
0x38 , // Negative integer of length 1
0x1c , // -29
0xc2 , // Tag 2 (positive bignum)
0x4d , // Byte string value of length 13
0x01 , 0x8e , 0xe9 , 0x0f , 0xf6 , 0xc3 , 0x73 , 0xe0 , 0xee , 0x4e , 0x3f , 0x0a , 0xd2 ,
0xff // "break"
};
jsoncons le permite trabajar con datos CBOR de manera similar a los datos JSON:
Como estructura de datos tipo variante, basic_json
Como una estructura de datos C++ fuertemente tipada que implementa json_type_traits
Con acceso a nivel de cursor a un flujo de eventos de análisis
int main ()
{
// Parse the CBOR data into a json value
json j = cbor::decode_cbor<json>(data);
// Pretty print
std::cout << " (1) n " << pretty_print (j) << " nn " ;
// Iterate over rows
std::cout << " (2) n " ;
for ( const auto & row : j. array_range ())
{
std::cout << row[ 1 ]. as <jsoncons::byte_string>() << " ( " << row[ 1 ]. tag () << " ) n " ;
}
std::cout << " n " ;
// Select the third column with JSONPath
std::cout << " (3) n " ;
json result = jsonpath::json_query (j, " $[*][2] " );
std::cout << pretty_print (result) << " nn " ;
// Serialize back to CBOR
std::vector< uint8_t > buffer;
cbor::encode_cbor (j, buffer);
std::cout << " (4) n " << byte_string_view (buffer) << " nn " ;
}
Producción:
(1)
[
["foo", "UHVzcw", "0x3p-1"],
["bar", "UHVzcw==", "1.23456789012345678901234567890"]
]
(2)
50,75,73,73 (n/a)
50,75,73,73 (base64)
(3)
[
"0x3p-1",
"1.23456789012345678901234567890"
]
(4)
82,83,63,66,6f,6f,44,50,75,73,73,c5,82,20,03,83,63,62,61,72,d6,44,50,75,73,73,c4,82,38,1c,c2,4d,01,8e,e9,0f,f6,c3,73,e0,ee,4e,3f,0a,d2
int main ()
{
// Parse the string of data into a std::vector<std::tuple<std::string,jsoncons::byte_string,std::string>> value
auto val = cbor::decode_cbor<std::vector<std::tuple<std::string,jsoncons::byte_string,std::string>>>(data);
std::cout << " (1) n " ;
for ( const auto & row : val)
{
std::cout << std::get< 0 >(row) << " , " << std::get< 1 >(row) << " , " << std::get< 2 >(row) << " n " ;
}
std::cout << " n " ;
// Serialize back to CBOR
std::vector< uint8_t > buffer;
cbor::encode_cbor (val, buffer);
std::cout << " (2) n " << byte_string_view (buffer) << " nn " ;
}
Producción:
(1)
foo, 50,75,73,73, 0x3p-1
bar, 50,75,73,73, 1.23456789012345678901234567890
(2)
82,9f,63,66,6f,6f,44,50,75,73,73,66,30,78,33,70,2d,31,ff,9f,63,62,61,72,44,50,75,73,73,78,1f,31,2e,32,33,34,35,36,37,38,39,30,31,32,33,34,35,36,37,38,39,30,31,32,33,34,35,36,37,38,39,30,ff
Tenga en cuenta que al decodificar la fracción decimal y bigfloat en un std::string
, perdemos la información semántica que la estructura de datos tipo variante conservó con una etiqueta, por lo que la serialización de nuevo a CBOR produce una cadena de texto.
Una aplicación típica de análisis pull procesará repetidamente el evento current()
y llamará next()
para avanzar al siguiente evento, hasta que done()
devuelva true
.
int main ()
{
cbor::cbor_bytes_cursor cursor (data);
for (; !cursor. done (); cursor. next ())
{
const auto & event = cursor. current ();
switch (event. event_type ())
{
case staj_event_type::begin_array:
std::cout << event. event_type () << " " << " ( " << event. tag () << " ) n " ;
break ;
case staj_event_type::end_array:
std::cout << event. event_type () << " " << " ( " << event. tag () << " ) n " ;
break ;
case staj_event_type::begin_object:
std::cout << event. event_type () << " " << " ( " << event. tag () << " ) n " ;
break ;
case staj_event_type::end_object:
std::cout << event. event_type () << " " << " ( " << event. tag () << " ) n " ;
break ;
case staj_event_type::key:
// Or std::string_view, if supported
std::cout << event. event_type () << " : " << event. get <jsoncons::string_view>() << " " << " ( " << event. tag () << " ) n " ;
break ;
case staj_event_type::string_value:
// Or std::string_view, if supported
std::cout << event. event_type () << " : " << event. get <jsoncons::string_view>() << " " << " ( " << event. tag () << " ) n " ;
break ;
case staj_event_type::byte_string_value:
std::cout << event. event_type () << " : " << event. get <jsoncons::span< const uint8_t >>() << " " << " ( " << event. tag () << " ) n " ;
break ;
case staj_event_type::null_value:
std::cout << event. event_type () << " " << " ( " << event. tag () << " ) n " ;
break ;
case staj_event_type::bool_value:
std::cout << event. event_type () << " : " << std::boolalpha << event. get < bool >() << " " << " ( " << event. tag () << " ) n " ;
break ;
case staj_event_type::int64_value:
std::cout << event. event_type () << " : " << event. get < int64_t >() << " " << " ( " << event. tag () << " ) n " ;
break ;
case staj_event_type::uint64_value:
std::cout << event. event_type () << " : " << event. get < uint64_t >() << " " << " ( " << event. tag () << " ) n " ;
break ;
case staj_event_type::half_value:
case staj_event_type::double_value:
std::cout << event. event_type () << " : " << event. get < double >() << " " << " ( " << event. tag () << " ) n " ;
break ;
default :
std::cout << " Unhandled event type " << event. event_type () << " " << " ( " << event. tag () << " ) n " ;
break ;
}
}
}
Producción:
begin_array (n/a)
begin_array (n/a)
string_value: foo (n/a)
byte_string_value: 50,75,73,73 (n/a)
string_value: 0x3p-1 (bigfloat)
end_array (n/a)
begin_array (n/a)
string_value: bar (n/a)
byte_string_value: 50,75,73,73 (base64)
string_value: 1.23456789012345678901234567890 (bigdec)
end_array (n/a)
end_array (n/a)
Puede aplicar un filtro a un cursor usando la sintaxis de canalización,
int main ()
{
auto filter = [&]( const staj_event& ev, const ser_context&) -> bool
{
return (ev. tag () == semantic_tag::bigdec) || (ev. tag () == semantic_tag::bigfloat);
};
cbor::cbor_bytes_cursor cursor (data);
auto filtered_c = cursor | filter;
for (; !filtered_c. done (); filtered_c. next ())
{
const auto & event = filtered_c. current ();
switch (event. event_type ())
{
case staj_event_type::string_value:
// Or std::string_view, if supported
std::cout << event. event_type () << " : " << event. get <jsoncons::string_view>() << " " << " ( " << event. tag () << " ) n " ;
break ;
default :
std::cout << " Unhandled event type " << event. event_type () << " " << " ( " << event. tag () << " ) n " ;
break ;
}
}
}
Producción:
string_value: 0x3p-1 (bigfloat)
string_value: 1.23456789012345678901234567890 (bigdec)
jsoncons requiere un compilador con soporte mínimo para C++11. Está probado en integración continua en Github Actions y Circleci. Los diagnósticos de UndefinedBehaviorSanitizer (UBSan) están habilitados para compilaciones gcc y clang seleccionadas. Desde la versión 0.151.0, está integrado con Google OSS-fuzz, con cobertura para todos los analizadores y codificadores.
Compilador | Versión | Estándar | Arquitectura | Sistema operativo | Servicio de CI |
---|---|---|---|---|---|
estudio visual | vs2019 | por defecto | x86, x64 | ventanas 11 | Acciones de GitHub |
vs2022 | por defecto | x86, x64 | ventanas 11 | Acciones de GitHub | |
Visual Studio - sonido metálico | vs2019 | por defecto | x86, x64 | ventanas 11 | Acciones de GitHub |
vs2022 | por defecto | x86, x64 | ventanas 11 | Acciones de GitHub | |
g++ | 6, 7, 8, 9, 10, 11, 12 | por defecto | x64 | ubuntu | circulo |
g++ | 12 | c++20 | x64 | ubuntu | Acciones de GitHub |
sonido metálico | 3.9, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 | por defecto | x64 | ubuntu | circulo |
sonido metálico | 14 | c++20 | x64 | ubuntu | Acciones de GitHub |
sonido metálico xcode | 11, 12, 13 | por defecto | x64 | OSX 11 | Acciones de GitHub |
sonido metálico xcode | 13, 14 | por defecto | x64 | OSX 12 | Acciones de GitHub |
CMake es una herramienta de compilación multiplataforma que genera archivos MAKE y soluciones para el entorno de compilación de su elección. En Windows puede descargar un paquete de Windows Installer. En Linux suele estar disponible como paquete, por ejemplo, en Ubuntu,
sudo apt-get install cmake
Una vez instalado cmake, puede compilar y ejecutar las pruebas unitarias desde el directorio jsoncons,
En Windows:
> mkdir build
> cd build
> cmake .. -DJSONCONS_BUILD_TESTS=On
> cmake --build .
> ctest -C Debug --output-on-failure
En UNIX:
$ mkdir build
$ cd build
$ cmake .. -DJSONCONS_BUILD_TESTS=On
$ cmake --build .
$ ctest --output-on-failure
jsoncons utiliza el analizador estático PVS-Studio, que se proporciona de forma gratuita para proyectos de código abierto.
Muchas gracias a la comunidad comp.lang.c++ por su ayuda con los detalles de implementación.
La configuración binaria dependiente de la plataforma jsoncons se basa en el excelente tinycbor con licencia del MIT.
Gracias a Milo Yip, autor de RapidJSON, por elevar la calidad de las bibliotecas JSON en todos los ámbitos, publicando los puntos de referencia y contactando a este proyecto (entre otros) para compartir los resultados.
La implementación jsoncons del algoritmo Grisu3 para imprimir números de punto flotante sigue la implementación grisu3_59_56 con licencia del MIT de Florian Loitsch, con modificaciones menores.
La macro JSONCONS_ALL_MEMBER_TRAITS
sigue el enfoque adoptado por ThorsSerializer de Martin York.
Las implementaciones jsoncons de BSON decimal128 hacia y desde una cadena, y ObjectId hacia y desde una cadena, se basan en libbson con licencia de Apache 2.
Un agradecimiento especial a nuestros colaboradores.