numam-spdk/lib/json/json_internal.h
Daniel Verkamp a509ddeb24 json/write: add an output buffer
This improves output speed significantly, especially if the write
callback is expensive (e.g. issues a syscall or takes a lock).

On my test system, jsoncat citylots.json > /dev/null improves from
~2.8s to ~1.7s.

citylots.json: https://github.com/zemirco/sf-city-lots-json (~181 MiB)

Change-Id: I7d411ce92366712ed87ad5fc6e9b64828541db4d
Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
2017-01-13 13:18:50 -07:00

295 lines
6.5 KiB
C

/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 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
* OWNER 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 SPDK_JSON_INTERNAL_H_
#define SPDK_JSON_INTERNAL_H_
#include "spdk/json.h"
#include <stdarg.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "spdk/likely.h"
#include "spdk/string.h"
#define SPDK_JSON_MAX_NESTING_DEPTH 64
static inline bool
utf8_tail(uint8_t c)
{
/* c >= 0x80 && c <= 0xBF, or binary 01xxxxxx */
return (c & 0xC0) == 0x80;
}
/*
* Check for a valid UTF-8 encoding of a single codepoint.
*
* \return Length of valid UTF-8 byte sequence, or negative if invalid.
*/
static inline int
utf8_valid(const uint8_t *start, const uint8_t *end)
{
const uint8_t *p = start;
uint8_t b0, b1, b2, b3;
if (p == end) {
return 0;
}
b0 = *p;
if (b0 <= 0x7F) {
return 1;
}
if (b0 <= 0xC1) {
/* Invalid start byte */
return -1;
}
if (++p == end) {
/* Not enough bytes left */
return -1;
}
b1 = *p;
if (b0 <= 0xDF) {
/* C2..DF 80..BF */
if (!utf8_tail(b1)) {
return -1;
}
return 2;
}
if (++p == end) {
/* Not enough bytes left */
return -1;
}
b2 = *p;
if (b0 == 0xE0) {
/* E0 A0..BF 80..BF */
if (b1 < 0xA0 || b1 > 0xBF || !utf8_tail(b2)) {
return -1;
}
return 3;
} else if (b0 == 0xED && b1 >= 0xA0) {
/*
* UTF-16 surrogate pairs use U+D800..U+DFFF, which would be encoded as
* ED A0..BF 80..BF in UTF-8; however, surrogate pairs are not allowed in UTF-8.
*/
return -1;
} else if (b0 <= 0xEF) {
/* E1..EF 80..BF 80..BF */
if (!utf8_tail(b1) || !utf8_tail(b2)) {
return -1;
}
return 3;
}
if (++p == end) {
/* Not enough bytes left */
return -1;
}
b3 = *p;
if (b0 == 0xF0) {
/* F0 90..BF 80..BF 80..BF */
if (b1 < 0x90 || b1 > 0xBF || !utf8_tail(b2) || !utf8_tail(b3)) {
return -1;
}
return 4;
} else if (b0 <= 0xF3) {
/* F1..F3 80..BF 80..BF 80..BF */
if (!utf8_tail(b1) || !utf8_tail(b2) || !utf8_tail(b3)) {
return -1;
}
return 4;
} else if (b0 == 0xF4) {
/* F4 80..8F 80..BF 80..BF */
if (b1 < 0x80 || b1 > 0x8F || !utf8_tail(b2) || !utf8_tail(b3)) {
return -1;
}
return 4;
}
return -1;
}
static inline uint32_t
utf8_decode_unsafe_1(const uint8_t *data)
{
return data[0];
}
static inline uint32_t
utf8_decode_unsafe_2(const uint8_t *data)
{
uint32_t codepoint;
codepoint = ((data[0] & 0x1F) << 6);
codepoint |= (data[1] & 0x3F);
return codepoint;
}
static inline uint32_t
utf8_decode_unsafe_3(const uint8_t *data)
{
uint32_t codepoint;
codepoint = ((data[0] & 0x0F) << 12);
codepoint |= (data[1] & 0x3F) << 6;
codepoint |= (data[2] & 0x3F);
return codepoint;
}
static inline uint32_t
utf8_decode_unsafe_4(const uint8_t *data)
{
uint32_t codepoint;
codepoint = ((data[0] & 0x07) << 18);
codepoint |= (data[1] & 0x3F) << 12;
codepoint |= (data[2] & 0x3F) << 6;
codepoint |= (data[3] & 0x3F);
return codepoint;
}
/*
* Encode a single Unicode codepoint as UTF-8.
*
* buf must have at least 4 bytes of space available (hence unsafe).
*
* \return Number of bytes appended to buf, or negative if encoding failed.
*/
static inline int
utf8_encode_unsafe(uint8_t *buf, uint32_t c)
{
if (c <= 0x7F) {
buf[0] = c;
return 1;
} else if (c <= 0x7FF) {
buf[0] = 0xC0 | (c >> 6);
buf[1] = 0x80 | (c & 0x3F);
return 2;
} else if (c >= 0xD800 && c <= 0xDFFF) {
/* UTF-16 surrogate pairs - invalid in UTF-8 */
return -1;
} else if (c <= 0xFFFF) {
buf[0] = 0xE0 | (c >> 12);
buf[1] = 0x80 | ((c >> 6) & 0x3F);
buf[2] = 0x80 | (c & 0x3F);
return 3;
} else if (c <= 0x10FFFF) {
buf[0] = 0xF0 | (c >> 18);
buf[1] = 0x80 | ((c >> 12) & 0x3F);
buf[2] = 0x80 | ((c >> 6) & 0x3F);
buf[3] = 0x80 | (c & 0x3F);
return 4;
}
return -1;
}
static inline int
utf8_codepoint_len(uint32_t c)
{
if (c <= 0x7F) {
return 1;
} else if (c <= 0x7FF) {
return 2;
} else if (c >= 0xD800 && c <= 0xDFFF) {
/* UTF-16 surrogate pairs - invalid in UTF-8 */
return -1;
} else if (c <= 0xFFFF) {
return 3;
} else if (c <= 0x10FFFF) {
return 4;
}
return -1;
}
static inline bool
utf16_valid_surrogate_high(uint32_t val)
{
return val >= 0xD800 && val <= 0xDBFF;
}
static inline bool
utf16_valid_surrogate_low(uint32_t val)
{
return val >= 0xDC00 && val <= 0xDFFF;
}
static inline uint32_t
utf16_decode_surrogate_pair(uint32_t high, uint32_t low)
{
uint32_t codepoint;
assert(utf16_valid_surrogate_high(high));
assert(utf16_valid_surrogate_low(low));
codepoint = low;
codepoint &= 0x3FF;
codepoint |= ((high & 0x3FF) << 10);
codepoint += 0x10000;
return codepoint;
}
static inline void
utf16_encode_surrogate_pair(uint32_t codepoint, uint16_t *high, uint16_t *low)
{
assert(codepoint >= 0x10000);
assert(codepoint <= 0x10FFFF);
codepoint -= 0x10000;
*high = 0xD800 | (codepoint >> 10);
*low = 0xDC00 | (codepoint & 0x3FF);
assert(utf16_valid_surrogate_high(*high));
assert(utf16_valid_surrogate_low(*low));
}
#endif