MPACK es una implementación C de un codificador y decodificador para el formato de serialización de MessagePack. Es:
El núcleo de MPACK contiene un lector y escritor amortiguado, y un analizador estilo árbol que decodifica en un árbol de nodos mecanografiados dinámicamente. Las funciones auxiliar se pueden habilitar para leer los valores del tipo esperado, trabajar con archivos, cultivar búferes o asignar cadenas automáticamente, para verificar la codificación UTF-8, y más.
El código mpack es lo suficientemente pequeño como para ser incrustado directamente en su base de código. Simplemente descargue el paquete de amalgamación y agregue mpack.h y mpack.c a su proyecto.
MPACK admite todos los compiladores modernos, todos los sistemas operativos de escritorio y teléfonos inteligentes, websembly, dentro del núcleo de Linux e incluso microcontroladores de 8 bits como Arduino. El MPACK FuncionET se puede personalizar en el tiempo de compilación para establecer qué características, componentes y verificaciones de depuración se compilan y qué dependencias están disponibles.
La API del nodo analiza una parte de los datos de MessagePack en un árbol inmutable de nodos de tipo dinámico. Se puede usar una serie de funciones auxiliares para extraer datos de tipos específicos de cada nodo.
// parse a file into a node tree
mpack_tree_t tree ;
mpack_tree_init_filename ( & tree , "homepage-example.mp" , 0 );
mpack_tree_parse ( & tree );
mpack_node_t root = mpack_tree_root ( & tree );
// extract the example data on the msgpack homepage
bool compact = mpack_node_bool ( mpack_node_map_cstr ( root , "compact" ));
int schema = mpack_node_i32 ( mpack_node_map_cstr ( root , "schema" ));
// clean up and check for errors
if ( mpack_tree_destroy ( & tree ) != mpack_ok ) {
fprintf ( stderr , "An error occurred decoding the data!n" );
return ;
}Tenga en cuenta que no se necesita manejo de errores adicionales en el código anterior. Si falta el archivo o corrupta, si faltan las teclas del mapa o si los nodos no están en los tipos esperados, se devuelven nodos especiales "nil" y valores falsos/cero y el árbol se coloca en un estado de error. Solo se necesita una verificación de error antes de usar los datos.
El ejemplo anterior asigna nodos automáticamente. En su lugar, se puede proporcionar un grupo de nodos fijo al analizador en entornos limitados por la memoria. Para el máximo rendimiento y el uso mínimo de la memoria, la API esperada se puede usar para analizar los datos de un esquema predefinido.
La API de escritura codifica datos estructurados en MessagePack.
// encode to memory buffer
char * data ;
size_t size ;
mpack_writer_t writer ;
mpack_writer_init_growable ( & writer , & data , & size );
// write the example on the msgpack homepage
mpack_build_map ( & writer );
mpack_write_cstr ( & writer , "compact" );
mpack_write_bool ( & writer , true);
mpack_write_cstr ( & writer , "schema" );
mpack_write_uint ( & writer , 0 );
mpack_complete_map ( & writer );
// finish writing
if ( mpack_writer_destroy ( & writer ) != mpack_ok ) {
fprintf ( stderr , "An error occurred encoding the data!n" );
return ;
}
// use the data
do_something_with_data ( data , size );
free ( data );En el ejemplo anterior, codificamos a un búfer de memoria Growable. En su lugar, el escritor puede escribir en un búfer pre alocado o alocado con pila (con tamaños iniciales para tipos de compuestos), evitando la necesidad de asignación de memoria. El escritor también se puede proporcionar con una función de descarga (como un archivo o una función de escritura de socket) para llamar cuando el búfer está lleno o cuando se realiza la escritura.
Si ocurre algún error, el escritor se coloca en un estado de error. El escritor marcará un error si se escriben demasiados datos, si se escribe el número incorrecto de elementos, si se produce una falla de asignación, si los datos no se pueden enjuagar, etc. No se necesita un manejo de errores adicional en el código anterior; Cualquier escritura posterior se ignora cuando el escritor está en un estado de error, por lo que no necesita verificar cada escritura para obtener errores.
El ejemplo anterior usa mpack_build_map() para determinar automáticamente el número de pares de valor clave contenidos. Si conoce por adelantado el número de elementos necesarios, puede pasarlo a mpack_start_map() en su lugar. En ese caso, el mpack_finish_map() correspondiente afirmará en modo de depuración que el número esperado de elementos realmente se escribió, que es algo que otras bibliotecas de mensajes C/C ++ pueden no hacer.
MPACK es rico en características mientras mantiene un rendimiento muy alto y una pequeña huella de código. Aquí hay una tabla de características corta que lo compara con otros analizadores C:
| Mpack (V1.1) | msgpack-c (v3.3.0) | CMP (V19) | Cwpack (V1.3.1) | |
|---|---|---|---|---|
| Sin requisito de libc | ✓ | ✓ | ✓ | |
| Escritor de memoria crecible | ✓ | ✓ | ✓* | |
| Ayudantes de E/S de archivo | ✓ | ✓ | ✓* | |
| Manejo de errores con estado | ✓ | ✓ | ||
| Analizador incremental | ✓ | ✓ | ✓ | |
| Analgésico | ✓ | ✓ | ||
| Seguimiento de tamaño compuesto | ✓ | |||
| Tamaño de compuesto automático | ✓ |
Aquí hay una tabla de comparación de características más grande que incluye descripciones de las diversas entradas en la tabla.
Esta suite de evaluación comparativa compara el rendimiento de MPACK con otras implementaciones de formatos de serialización de esquemas. MPACK supera a todas las bibliotecas JSON y MessagePack (excepto CWPACK), y en algunas pruebas MPACK es varias veces más rápido que Rapidjson para datos equivalentes.
Conceptualmente, MessagePack almacena datos de manera similar a JSON: ambos están compuestos por valores simples como números y cadenas, almacenados jerárquicamente en mapas y matrices. Entonces, ¿por qué no usar JSON en su lugar? La razón principal es que JSON está diseñado para ser legible por humanos, por lo que no es tan eficiente como un formato de serialización binaria:
Los tipos de compuestos, como cadenas, mapas y matrices, se delimitan, por lo que el almacenamiento apropiado no se puede asignar por adelantado. Todo el objeto debe analizarse para determinar su tamaño.
Las cadenas no se almacenan en su codificación nativa. Los caracteres especiales, como citas y invertidos, deben escaparse cuando se escriben y se convierten cuando se lean.
Los números son particularmente ineficientes (especialmente al analizar flotadores), lo que hace que JSON sea inapropiado como un formato base para datos estructurados que contienen muchos números.
Los datos binarios no son compatibles con JSON en absoluto. Las pequeñas manchas binarias, como los íconos y las miniaturas, deben estar codificadas o pasadas de banda base64.
Los problemas anteriores aumentan en gran medida la complejidad del decodificador. Los decodificadores JSON con todas las funciones son bastante grandes, y los decodificadores mínimos tienden a dejar de lado características tales como un análisis de sincaping y flotación, en lugar de dejarlos al usuario o plataforma. Esto puede conducir a errores específicos de plataforma y específicos de la plataforma difíciles de encontrar, así como a un mayor potencial para los vulnerabilitos de seguridad. Esto también disminuye significativamente el rendimiento, lo que hace que JSON sea poco atractivo para su uso en aplicaciones como juegos móviles.
Si bien las ineficiencias espaciales de JSON pueden mitigarse parcialmente a través de la minificación y la compresión, las ineficiencias de rendimiento no pueden. Más importante aún, si está minificando y comprimiendo los datos, ¿por qué utilizar un formato legible por humanos en primer lugar?
El proceso de compilación mpack no incorpora mpack en una biblioteca; Se usa para construir y ejecutar las pruebas unitarias. No necesita construir mpack o la suite de prueba unitaria para usar mpack.
Consulte Test/ReadMe.MD para obtener información sobre cómo probar MPACK.