jsoncons — это C++ библиотека только для заголовков, предназначенная для создания JSON и JSON-подобных форматов данных, таких как CBOR. Для каждого поддерживаемого формата данных он позволяет работать с данными несколькими способами:
В качестве вариантной структуры данных с поддержкой распределителя, Basic_json
Как строго типизированная структура данных C++, реализующая json_type_traits.
С доступом на уровне курсора к потоку событий синтаксического анализа, что в некоторой степени аналогично синтаксическому анализу StAX и сериализации push в мире XML.
По сравнению с другими библиотеками JSON, jsoncons была разработана для обработки очень больших текстов JSON. В основе лежат парсеры и сериализаторы в стиле SAX. Он поддерживает чтение всего текста JSON в памяти в вариантной структуре. Но он также поддерживает эффективный доступ к базовым данным с помощью анализа запросов и сериализации в стиле StAX. И он поддерживает инкрементный анализ в предпочитаемую пользователем форму, используя информацию о типах пользователей, предоставляемую специализациями json_type_traits.
Модель данных jsoncons поддерживает знакомые типы JSON — значения NULL, логические значения, числа, строки, массивы, объекты — а также байтовые строки. Кроме того, jsoncons поддерживает семантическую маркировку дат и времен, эпох, больших целых чисел, больших десятичных чисел, больших чисел с плавающей запятой и двоичных кодировок. Это позволяет ему сохранять семантику этих типов при анализе форматов данных, подобных JSON, таких как CBOR, в которых они есть.
jsoncons распространяется по лицензии Boost Software License.
jsoncons бесплатен, но приветствуется поддержка для поддержания его развития. Если вы считаете эту библиотеку полезной, рассмотрите возможность сделать единоразовое пожертвование или стать спонсором ❤️.
По мере развития библиотеки jsoncons
имена иногда менялись. Чтобы облегчить переход, jsoncons отказывается от старых имен, но продолжает поддерживать многие из них. Устаревшие имена можно подавить, определив макрос JSONCONS_NO_DEPRECATED
, и это рекомендуется для нового кода.
«Apache Kvrocks постоянно использует jsoncons, чтобы предложить пользователям поддержку структур данных JSON. Мы считаем опыт разработки с jsoncons выдающимся!»
«Я использовал вашу библиотеку на моем родном языке — R — и создал пакет R, упрощающий (а) запросы JMESpath и JSONpath к строкам JSON или объектам R и (б) другим разработчикам R возможность ссылаться на вашу библиотеку. ."
«Я использую вашу библиотеку в качестве внешнего интерфейса для передачи данных, а также использую преобразования из CSV в JSON, которые очень полезны для преобразования данных для использования в JavaScript»
«Проверено, что для моих нужд в JSON и CBOR все работает отлично»
«Функция JSONPath в этой библиотеке — это здорово»
«Мы довольно широко используем реализацию JMESPath»
«Нам нравится ваш валидатор схемы JSON. Мы используем его в ER/Studio, нашем инструменте моделирования данных, для анализа файлов схемы JSON и создания на их основе моделей отношений сущностей».
«предпочтительная библиотека сериализации с ее красивыми сопоставлениями и простотой использования»
"действительно хорошо" "потрясающий проект" "очень солидный и очень надежный" "моей команде это нравится" "Ваш репозиторий просто потрясающий!!!!!"
Начните работу с наборами изображений и фреймами изображений HealthImaging с помощью AWS SDK
RubyGems.org rjsoncons Лицензии Coppelia Robotics CSPro
Вы можете использовать менеджер библиотек платформы vcpkg для установки пакета jsoncons.
Или загрузите последнюю версию и распакуйте zip-файл. Скопируйте каталог include/jsoncons
в каталог include
. Если вы хотите использовать расширения, скопируйте также include/jsoncons_ext
.
Или загрузите последнюю версию кода на странице main.
Для библиотеки требуется компилятор C++ с поддержкой C++11. Кроме того, библиотека определяет jsoncons::endian
, jsoncons::basic_string_view
, jsoncons::optional
и jsoncons::span
, которым при обнаружении будет присвоен тип их эквивалентов в стандартной библиотеке. В противном случае они будут определены для внутренних реализаций, совместимых с C++11.
Библиотека использует исключения и в некоторых случаях std::error_code для сообщения об ошибках. Помимо jsoncons::assertion_error
, все классы исключений jsoncons реализуют интерфейс jsoncons::json_error. Если исключения отключены или если определен макрос времени компиляции JSONCONS_NO_EXCEPTIONS
, броски становятся вызовами std::terminate
.
json_benchmarks предоставляет некоторые данные о сравнении jsoncons
с другими библиотеками json
.
Наборы тестов JSONTestSuite и JSON_checker
Тесты производительности с текстом и целыми числами
Тесты производительности с текстом и двойниками
Сравнение JSONPath показывает, как jsoncons JsonPath сравнивается с другими реализациями.
Работа с данными JSON
Работа с данными CBOR
Для приведенных ниже примеров вам необходимо включить несколько файлов заголовков и инициализировать строку данных 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 позволяет работать с данными несколькими способами:
Как вариантная структура данных, Basic_json
Как строго типизированная структура данных C++, реализующая json_type_traits.
С доступом на уровне курсора к потоку событий синтаксического анализа
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 " ;
}
Выход:
(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 поддерживает преобразование текстов JSON в структуры данных C++. Функции decode_json и encode_json преобразуют строки или потоки данных JSON в структуры данных C++ и обратно. Декодирование и кодирование работают для всех классов C++, в которых определен json_type_traits. jsoncons уже поддерживает множество типов в стандартной библиотеке, и ваши собственные типы также будут поддерживаться, если вы специализируете json_type_traits
в пространстве имен 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 " ;
}
Выход:
(1)
Marilyn C, 0.9, 1514862245
(2)
{
"application": "hiking",
"reputons": [
{
"assertion": "advanced",
"generated": 1514862245,
"rated": "Marilyn C",
"rater": "HikingAsylum",
"rating": 0.9
}
]
}
В этом примере используются удобные макросы JSONCONS_ENUM_TRAITS
, JSONCONS_N_CTOR_GETTER_TRAITS
и JSONCONS_ALL_CTOR_GETTER_TRAITS
для специализации json_type_traits для типа перечисления ns::hiking_experience
, класса ns::hiking_reputon
(с некоторыми необязательными членами) и класса ns::hiking_reputation
(со всеми обязательными членами.) Макрос JSONCONS_ENUM_TRAITS
генерирует код из идентификаторов перечисления, а макросы JSONCONS_N_CTOR_GETTER_TRAITS
и JSONCONS_ALL_CTOR_GETTER_TRAITS
генерируют код из функций get и конструктора. Эти объявления макросов должны быть размещены вне любых блоков пространства имен.
См. примеры других способов специализации json_type_traits
.
Типичное приложение синтаксического анализа по запросу будет неоднократно обрабатывать событие current()
и вызывать next()
для перехода к следующему событию, пока done()
вернет 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 ;
}
}
}
Выход:
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
Вы можете применить фильтр к курсору, используя синтаксис канала (например, 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 ;
}
}
}
Выход:
Marilyn C
Для приведенных ниже примеров вам необходимо включить несколько заголовочных файлов и инициализировать буфер данных 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 позволяет работать с данными CBOR аналогично данным JSON:
Как вариантная структура данных, Basic_json
Как строго типизированная структура данных C++, реализующая json_type_traits.
С доступом на уровне курсора к потоку событий синтаксического анализа
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 " ;
}
Выход:
(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 " ;
}
Выход:
(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
Обратите внимание, что при декодировании bigfloat и десятичной дроби в std::string
мы теряем семантическую информацию, которую вариант структуры данных сохраняет с помощью тега, поэтому сериализация обратно в CBOR создает текстовую строку.
Типичное приложение синтаксического анализа по запросу будет неоднократно обрабатывать событие current()
и вызывать next()
для перехода к следующему событию, пока done()
вернет 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 ;
}
}
}
Выход:
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)
Вы можете применить фильтр к курсору, используя синтаксис канала:
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 ;
}
}
}
Выход:
string_value: 0x3p-1 (bigfloat)
string_value: 1.23456789012345678901234567890 (bigdec)
jsoncons требует компилятора с минимальной поддержкой C++11. Он протестирован в непрерывной интеграции на Github Actions и Circleci. Диагностика UndefineBehaviorSanitizer (UBSan) включена для выбранных сборок gcc и clang. Начиная с версии 0.151.0, он интегрирован с Google OSS-fuzz и охватывает все парсеры и кодировщики.
Компилятор | Версия | Стандартный | Архитектура | Операционная система | CI-сервис |
---|---|---|---|---|---|
Визуальная Студия | vs2019 | по умолчанию | х86, х64 | Windows 11 | Действия GitHub |
vs2022 | по умолчанию | х86, х64 | Windows 11 | Действия GitHub | |
Visual Studio — лязг | vs2019 | по умолчанию | х86, х64 | Windows 11 | Действия GitHub |
vs2022 | по умолчанию | х86, х64 | Windows 11 | Действия GitHub | |
г++ | 6, 7, 8, 9, 10, 11, 12 | по умолчанию | х64 | Убунту | кружочки |
г++ | 12 | С++20 | х64 | Убунту | Действия GitHub |
лязг | 3,9, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 | по умолчанию | х64 | Убунту | кружочки |
лязг | 14 | С++20 | х64 | Убунту | Действия GitHub |
лязг xcode | 11, 12, 13 | по умолчанию | х64 | ОС X 11 | Действия GitHub |
лязг xcode | 13, 14 | по умолчанию | х64 | ОС X 12 | Действия GitHub |
CMake — это кроссплатформенный инструмент сборки, который генерирует make-файлы и решения для среды компилятора по вашему выбору. В Windows вы можете загрузить пакет установщика Windows. В Linux он обычно доступен в виде пакета, например в Ubuntu
sudo apt-get install cmake
После установки cmake вы можете создавать и запускать модульные тесты из каталога jsoncons.
В Windows:
> mkdir build
> cd build
> cmake .. -DJSONCONS_BUILD_TESTS=On
> cmake --build .
> ctest -C Debug --output-on-failure
В UNIX:
$ mkdir build
$ cd build
$ cmake .. -DJSONCONS_BUILD_TESTS=On
$ cmake --build .
$ ctest --output-on-failure
jsoncons использует статический анализатор PVS-Studio, который бесплатно предоставляется для проектов с открытым исходным кодом.
Большое спасибо сообществу comp.lang.c++ за помощь в деталях реализации.
Бинарная конфигурация, зависящая от платформы jsoncons, опирается на превосходную версию tinycbor, лицензированную MIT.
Спасибо Майло Йипу, автору RapidJSON, за повышение качества библиотек JSON по всем направлениям, публикацию тестов и обращение к этому проекту (среди других), чтобы поделиться результатами.
Реализация jsoncons алгоритма Grisu3 для печати чисел с плавающей запятой соответствует реализации grisu3_59_56 Флориана Лойча, лицензированной MIT, с небольшими изменениями.
Макрос JSONCONS_ALL_MEMBER_TRAITS
соответствует подходу, использованному ThorsSerializer Мартина Йорка.
Реализации jsoncons BSON decimal128 в строку и из нее, а также ObjectId в строку и из нее основаны на лицензированной версии libbson Apache 2.
Особая благодарность нашим участникам