#ifndef RAPIDJSON_READER_H_
#define RAPIDJSON_READER_H_
#include "allocators.h"
#include "stream.h"
#include "encodedstream.h"
#include "internal/clzll.h"
#include "internal/meta.h"
#include "internal/stack.h"
#include "internal/strtod.h"
#include <limits>
#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
#include <intrin.h>
#pragma intrinsic(_BitScanForward)
#endif
#ifdef RAPIDJSON_SSE42
#include <nmmintrin.h>
#elif defined(RAPIDJSON_SSE2)
#include <emmintrin.h>
#elif defined(RAPIDJSON_NEON)
#include <arm_neon.h>
#endif
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(…)
RAPIDJSON_DIAG_OFF(…)
RAPIDJSON_DIAG_OFF(…)
#elif defined(_MSC_VER)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4127)
RAPIDJSON_DIAG_OFF(4702)
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(…)
#endif
#define RAPIDJSON_NOTHING …
#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) …
#endif
#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID …
#ifndef RAPIDJSON_PARSE_ERROR_NORETURN
#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) …
#endif
#ifndef RAPIDJSON_PARSE_ERROR
#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) …
#endif
#include "error/error.h"
RAPIDJSON_NAMESPACE_BEGIN
#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS
#define RAPIDJSON_PARSE_DEFAULT_FLAGS …
#endif
enum ParseFlag { … };
template<typename Encoding = UTF8<>, typename Derived = void>
struct BaseReaderHandler { … };
namespace internal {
template<typename Stream, int = StreamTraits<Stream>::copyOptimization>
class StreamLocalCopy;
StreamLocalCopy<Stream, 1>;
StreamLocalCopy<Stream, 0>;
}
template<typename InputStream>
void SkipWhitespace(InputStream& is) { … }
inline const char* SkipWhitespace(const char* p, const char* end) { … }
#ifdef RAPIDJSON_SSE42
inline const char *SkipWhitespace_SIMD(const char* p) {
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p;
else
return p;
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
while (p != nextAligned)
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p;
else
return p;
static const char whitespace[16] = " \n\r\t";
const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));
for (;; p += 16) {
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY);
if (r != 16)
return p + r;
}
}
inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
++p;
else
return p;
static const char whitespace[16] = " \n\r\t";
const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));
for (; p <= end - 16; p += 16) {
const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY);
if (r != 16)
return p + r;
}
return SkipWhitespace(p, end);
}
#elif defined(RAPIDJSON_SSE2)
inline const char *SkipWhitespace_SIMD(const char* p) {
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p;
else
return p;
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
while (p != nextAligned)
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p;
else
return p;
#define C16 …
static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') };
#undef C16
const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));
const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));
const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));
const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));
for (;; p += 16) {
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
__m128i x = _mm_cmpeq_epi8(s, w0);
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
if (r != 0) {
#ifdef _MSC_VER
unsigned long offset;
_BitScanForward(&offset, r);
return p + offset;
#else
return p + __builtin_ffs(r) - 1;
#endif
}
}
}
inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
++p;
else
return p;
#define C16 …
static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') };
#undef C16
const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));
const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));
const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));
const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));
for (; p <= end - 16; p += 16) {
const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
__m128i x = _mm_cmpeq_epi8(s, w0);
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
if (r != 0) {
#ifdef _MSC_VER
unsigned long offset;
_BitScanForward(&offset, r);
return p + offset;
#else
return p + __builtin_ffs(r) - 1;
#endif
}
}
return SkipWhitespace(p, end);
}
#elif defined(RAPIDJSON_NEON)
inline const char *SkipWhitespace_SIMD(const char* p) {
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p;
else
return p;
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
while (p != nextAligned)
if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
++p;
else
return p;
const uint8x16_t w0 = vmovq_n_u8(' ');
const uint8x16_t w1 = vmovq_n_u8('\n');
const uint8x16_t w2 = vmovq_n_u8('\r');
const uint8x16_t w3 = vmovq_n_u8('\t');
for (;; p += 16) {
const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
uint8x16_t x = vceqq_u8(s, w0);
x = vorrq_u8(x, vceqq_u8(s, w1));
x = vorrq_u8(x, vceqq_u8(s, w2));
x = vorrq_u8(x, vceqq_u8(s, w3));
x = vmvnq_u8(x);
x = vrev64q_u8(x);
uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0);
uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1);
if (low == 0) {
if (high != 0) {
uint32_t lz = internal::clzll(high);
return p + 8 + (lz >> 3);
}
} else {
uint32_t lz = internal::clzll(low);
return p + (lz >> 3);
}
}
}
inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
++p;
else
return p;
const uint8x16_t w0 = vmovq_n_u8(' ');
const uint8x16_t w1 = vmovq_n_u8('\n');
const uint8x16_t w2 = vmovq_n_u8('\r');
const uint8x16_t w3 = vmovq_n_u8('\t');
for (; p <= end - 16; p += 16) {
const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
uint8x16_t x = vceqq_u8(s, w0);
x = vorrq_u8(x, vceqq_u8(s, w1));
x = vorrq_u8(x, vceqq_u8(s, w2));
x = vorrq_u8(x, vceqq_u8(s, w3));
x = vmvnq_u8(x);
x = vrev64q_u8(x);
uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0);
uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1);
if (low == 0) {
if (high != 0) {
uint32_t lz = internal::clzll(high);
return p + 8 + (lz >> 3);
}
} else {
uint32_t lz = internal::clzll(low);
return p + (lz >> 3);
}
}
return SkipWhitespace(p, end);
}
#endif
#ifdef RAPIDJSON_SIMD
template<> inline void SkipWhitespace(InsituStringStream& is) {
is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));
}
template<> inline void SkipWhitespace(StringStream& is) {
is.src_ = SkipWhitespace_SIMD(is.src_);
}
template<> inline void SkipWhitespace(EncodedInputStream<UTF8<>, MemoryStream>& is) {
is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_);
}
#endif
template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator = CrtAllocator>
class GenericReader { … };
Reader;
RAPIDJSON_NAMESPACE_END
#if defined(__clang__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
#endif