Added preset system for FM IF NR

This commit is contained in:
AlexandreRouma 2021-12-24 21:42:04 +01:00
parent ad2ddc6ad3
commit 07294034f6
53 changed files with 6538 additions and 5603 deletions

View File

@ -13,6 +13,13 @@ enum DeemphasisMode {
_DEEMP_MODE_COUNT _DEEMP_MODE_COUNT
}; };
enum IFNRPreset {
IFNR_PRESET_NOAA_APT,
IFNR_PRESET_VOICE,
IFNR_PRESET_NARROW_BAND,
IFNR_PRESET_BROADCAST
};
namespace demod { namespace demod {
class Demodulator { class Demodulator {
public: public:

View File

@ -22,6 +22,13 @@ std::map<DeemphasisMode, double> deempTaus = {
{ DEEMP_MODE_75US, 75e-6 } { DEEMP_MODE_75US, 75e-6 }
}; };
std::map<IFNRPreset, double> ifnrTaps = {
{ IFNR_PRESET_NOAA_APT, 9},
{ IFNR_PRESET_VOICE, 15 },
{ IFNR_PRESET_NARROW_BAND, 31 },
{ IFNR_PRESET_BROADCAST, 32 }
};
class RadioModule : public ModuleManager::Instance { class RadioModule : public ModuleManager::Instance {
public: public:
RadioModule(std::string name) { RadioModule(std::string name) {
@ -33,6 +40,10 @@ public:
deempModes.define("50us", DEEMP_MODE_50US); deempModes.define("50us", DEEMP_MODE_50US);
deempModes.define("75us", DEEMP_MODE_75US); deempModes.define("75us", DEEMP_MODE_75US);
ifnrPresets.define("NOAA APT", IFNR_PRESET_NOAA_APT);
ifnrPresets.define("Voice", IFNR_PRESET_VOICE);
ifnrPresets.define("Narrow Band", IFNR_PRESET_NARROW_BAND);
// Initialize the config if it doesn't exist // Initialize the config if it doesn't exist
bool created = false; bool created = false;
config.acquire(); config.acquire();
@ -297,6 +308,15 @@ private:
if (ImGui::Checkbox(("IF Noise Reduction##_radio_fmifnr_ena_" + _this->name).c_str(), &_this->FMIFNREnabled)) { if (ImGui::Checkbox(("IF Noise Reduction##_radio_fmifnr_ena_" + _this->name).c_str(), &_this->FMIFNREnabled)) {
_this->setFMIFNREnabled(_this->FMIFNREnabled); _this->setFMIFNREnabled(_this->FMIFNREnabled);
} }
if (_this->selectedDemodID == RADIO_DEMOD_NFM) {
if (!_this->FMIFNREnabled && _this->enabled) { style::beginDisabled(); }
ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::Combo(("##_radio_fmifnr_ena_" + _this->name).c_str(), &_this->fmIFPresetId, _this->ifnrPresets.txt)) {
_this->setIFNRPreset(_this->ifnrPresets[_this->fmIFPresetId]);
}
if (!_this->FMIFNREnabled && _this->enabled) { style::endDisabled(); }
}
} }
// Demodulator specific menu // Demodulator specific menu
@ -347,6 +367,7 @@ private:
postProcEnabled = selectedDemod->getPostProcEnabled(); postProcEnabled = selectedDemod->getPostProcEnabled();
FMIFNRAllowed = selectedDemod->getFMIFNRAllowed(); FMIFNRAllowed = selectedDemod->getFMIFNRAllowed();
FMIFNREnabled = false; FMIFNREnabled = false;
fmIFPresetId = ifnrPresets.valueId(IFNR_PRESET_VOICE);
nbAllowed = selectedDemod->getNBAllowed(); nbAllowed = selectedDemod->getNBAllowed();
nbEnabled = false; nbEnabled = false;
nbLevel = 0.0f; nbLevel = 0.0f;
@ -365,7 +386,6 @@ private:
squelchEnabled = config.conf[name][selectedDemod->getName()]["squelchEnabled"]; squelchEnabled = config.conf[name][selectedDemod->getName()]["squelchEnabled"];
} }
if (config.conf[name][selectedDemod->getName()].contains("deempMode")) { if (config.conf[name][selectedDemod->getName()].contains("deempMode")) {
// Upgrade to the text key
if (!config.conf[name][selectedDemod->getName()]["deempMode"].is_string()) { if (!config.conf[name][selectedDemod->getName()]["deempMode"].is_string()) {
config.conf[name][selectedDemod->getName()]["deempMode"] = deempModes.key(deempId); config.conf[name][selectedDemod->getName()]["deempMode"] = deempModes.key(deempId);
} }
@ -378,6 +398,12 @@ private:
if (config.conf[name][selectedDemod->getName()].contains("FMIFNREnabled")) { if (config.conf[name][selectedDemod->getName()].contains("FMIFNREnabled")) {
FMIFNREnabled = config.conf[name][selectedDemod->getName()]["FMIFNREnabled"]; FMIFNREnabled = config.conf[name][selectedDemod->getName()]["FMIFNREnabled"];
} }
if (config.conf[name][selectedDemod->getName()].contains("fmifnrPreset")) {
std::string presetOpt = config.conf[name][selectedDemod->getName()]["fmifnrPreset"];
if (ifnrPresets.keyExists(presetOpt)) {
fmIFPresetId = ifnrPresets.keyId(presetOpt);
}
}
if (config.conf[name][selectedDemod->getName()].contains("noiseBlankerEnabled")) { if (config.conf[name][selectedDemod->getName()].contains("noiseBlankerEnabled")) {
nbEnabled = config.conf[name][selectedDemod->getName()]["noiseBlankerEnabled"]; nbEnabled = config.conf[name][selectedDemod->getName()]["noiseBlankerEnabled"];
} }
@ -401,6 +427,7 @@ private:
setBandwidth(bandwidth); setBandwidth(bandwidth);
// Configure FM IF Noise Reduction // Configure FM IF Noise Reduction
setIFNRPreset((selectedDemodID == RADIO_DEMOD_NFM) ? ifnrPresets[fmIFPresetId] : IFNR_PRESET_BROADCAST);
setFMIFNREnabled(FMIFNRAllowed ? FMIFNREnabled : false); setFMIFNREnabled(FMIFNRAllowed ? FMIFNREnabled : false);
// Configure notch // Configure notch
@ -411,7 +438,6 @@ private:
setSquelchEnabled(squelchEnabled); setSquelchEnabled(squelchEnabled);
// Configure noise blanker // Configure noise blanker
fmnr.block.setTapCount((selectedDemod->getIFSampleRate() < 100000.0f) ? 9 : 32);
nb.block.setLevel(nbLevel); nb.block.setLevel(nbLevel);
setNoiseBlankerEnabled(nbEnabled); setNoiseBlankerEnabled(nbEnabled);
@ -555,6 +581,24 @@ private:
config.release(true); config.release(true);
} }
void setIFNRPreset(IFNRPreset preset) {
// Don't save if in broadcast mode
if (preset == IFNR_PRESET_BROADCAST) {
if (!selectedDemod) { return; }
fmnr.block.setTapCount(ifnrTaps[preset]);
return;
}
fmIFPresetId = ifnrPresets.valueId(preset);
if (!selectedDemod) { return; }
fmnr.block.setTapCount(ifnrTaps[preset]);
// Save config
config.acquire();
config.conf[name][selectedDemod->getName()]["fmifnrPreset"] = ifnrPresets.key(fmIFPresetId);
config.release(true);
}
static void vfoUserChangedBandwidthHandler(double newBw, void* ctx) { static void vfoUserChangedBandwidthHandler(double newBw, void* ctx) {
RadioModule* _this = (RadioModule*)ctx; RadioModule* _this = (RadioModule*)ctx;
_this->setBandwidth(newBw); _this->setBandwidth(newBw);
@ -655,6 +699,7 @@ private:
demod::Demodulator* selectedDemod = NULL; demod::Demodulator* selectedDemod = NULL;
OptionList<std::string, DeemphasisMode> deempModes; OptionList<std::string, DeemphasisMode> deempModes;
OptionList<std::string, IFNRPreset> ifnrPresets;
double audioSampleRate = 48000.0; double audioSampleRate = 48000.0;
float minBandwidth; float minBandwidth;
@ -673,6 +718,7 @@ private:
bool FMIFNRAllowed; bool FMIFNRAllowed;
bool FMIFNREnabled = false; bool FMIFNREnabled = false;
int fmIFPresetId;
bool notchEnabled = false; bool notchEnabled = false;
float notchPos = 0; float notchPos = 0;

View File

@ -58,11 +58,11 @@ typedef struct DiscordEventHandlers {
void (*joinRequest)(const DiscordUser* request); void (*joinRequest)(const DiscordUser* request);
} DiscordEventHandlers; } DiscordEventHandlers;
#define DISCORD_REPLY_NO 0 #define DISCORD_REPLY_NO 0
#define DISCORD_REPLY_YES 1 #define DISCORD_REPLY_YES 1
#define DISCORD_REPLY_IGNORE 2 #define DISCORD_REPLY_IGNORE 2
#define DISCORD_PARTY_PRIVATE 0 #define DISCORD_PARTY_PRIVATE 0
#define DISCORD_PARTY_PUBLIC 1 #define DISCORD_PARTY_PUBLIC 1
DISCORD_EXPORT void Discord_Initialize(const char* applicationId, DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
DiscordEventHandlers* handlers, DiscordEventHandlers* handlers,

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ALLOCATORS_H_ #ifndef RAPIDJSON_ALLOCATORS_H_
@ -82,7 +82,7 @@ concept Allocator {
class CrtAllocator { class CrtAllocator {
public: public:
static const bool kNeedFree = true; static const bool kNeedFree = true;
void* Malloc(size_t size) { void* Malloc(size_t size) {
if (size) // behavior of malloc(0) is implementation defined. if (size) // behavior of malloc(0) is implementation defined.
return RAPIDJSON_MALLOC(size); return RAPIDJSON_MALLOC(size);
else else
@ -96,7 +96,7 @@ public:
} }
return RAPIDJSON_REALLOC(originalPtr, newSize); return RAPIDJSON_REALLOC(originalPtr, newSize);
} }
static void Free(void *ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); } static void Free(void* ptr) RAPIDJSON_NOEXCEPT { RAPIDJSON_FREE(ptr); }
bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT { bool operator==(const CrtAllocator&) const RAPIDJSON_NOEXCEPT {
return true; return true;
@ -131,13 +131,13 @@ class MemoryPoolAllocator {
/*! Chunks are stored as a singly linked list. /*! Chunks are stored as a singly linked list.
*/ */
struct ChunkHeader { struct ChunkHeader {
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
size_t size; //!< Current size of allocated memory in bytes. size_t size; //!< Current size of allocated memory in bytes.
ChunkHeader *next; //!< Next chunk in the linked list. ChunkHeader* next; //!< Next chunk in the linked list.
}; };
struct SharedData { struct SharedData {
ChunkHeader *chunkHead; //!< Head of the chunk linked-list. Only the head chunk serves allocation. ChunkHeader* chunkHead; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
BaseAllocator* ownBaseAllocator; //!< base allocator created by this object. BaseAllocator* ownBaseAllocator; //!< base allocator created by this object.
size_t refcount; size_t refcount;
bool ownBuffer; bool ownBuffer;
@ -146,31 +146,26 @@ class MemoryPoolAllocator {
static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData)); static const size_t SIZEOF_SHARED_DATA = RAPIDJSON_ALIGN(sizeof(SharedData));
static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader)); static const size_t SIZEOF_CHUNK_HEADER = RAPIDJSON_ALIGN(sizeof(ChunkHeader));
static inline ChunkHeader *GetChunkHead(SharedData *shared) static inline ChunkHeader* GetChunkHead(SharedData* shared) {
{
return reinterpret_cast<ChunkHeader*>(reinterpret_cast<uint8_t*>(shared) + SIZEOF_SHARED_DATA); return reinterpret_cast<ChunkHeader*>(reinterpret_cast<uint8_t*>(shared) + SIZEOF_SHARED_DATA);
} }
static inline uint8_t *GetChunkBuffer(SharedData *shared) static inline uint8_t* GetChunkBuffer(SharedData* shared) {
{
return reinterpret_cast<uint8_t*>(shared->chunkHead) + SIZEOF_CHUNK_HEADER; return reinterpret_cast<uint8_t*>(shared->chunkHead) + SIZEOF_CHUNK_HEADER;
} }
static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity. static const size_t kDefaultChunkCapacity = RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
public: public:
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
static const bool kRefCounted = true; //!< Tell users that this allocator is reference counted on copy static const bool kRefCounted = true; //!< Tell users that this allocator is reference counted on copy
//! Constructor with chunkSize. //! Constructor with chunkSize.
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks. \param baseAllocator The allocator for allocating memory chunks.
*/ */
explicit explicit MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : chunk_capacity_(chunkSize),
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()),
chunk_capacity_(chunkSize), shared_(static_cast<SharedData*>(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0)) {
baseAllocator_(baseAllocator ? baseAllocator : RAPIDJSON_NEW(BaseAllocator)()),
shared_(static_cast<SharedData*>(baseAllocator_ ? baseAllocator_->Malloc(SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER) : 0))
{
RAPIDJSON_ASSERT(baseAllocator_ != 0); RAPIDJSON_ASSERT(baseAllocator_ != 0);
RAPIDJSON_ASSERT(shared_ != 0); RAPIDJSON_ASSERT(shared_ != 0);
if (baseAllocator) { if (baseAllocator) {
@ -197,11 +192,9 @@ public:
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize. \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks. \param baseAllocator The allocator for allocating memory chunks.
*/ */
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : MemoryPoolAllocator(void* buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : chunk_capacity_(chunkSize),
chunk_capacity_(chunkSize), baseAllocator_(baseAllocator),
baseAllocator_(baseAllocator), shared_(static_cast<SharedData*>(AlignBuffer(buffer, size))) {
shared_(static_cast<SharedData*>(AlignBuffer(buffer, size)))
{
RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER); RAPIDJSON_ASSERT(size >= SIZEOF_SHARED_DATA + SIZEOF_CHUNK_HEADER);
shared_->chunkHead = GetChunkHead(shared_); shared_->chunkHead = GetChunkHead(shared_);
shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER; shared_->chunkHead->capacity = size - SIZEOF_SHARED_DATA - SIZEOF_CHUNK_HEADER;
@ -212,16 +205,13 @@ public:
shared_->refcount = 1; shared_->refcount = 1;
} }
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT : MemoryPoolAllocator(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT : chunk_capacity_(rhs.chunk_capacity_),
chunk_capacity_(rhs.chunk_capacity_), baseAllocator_(rhs.baseAllocator_),
baseAllocator_(rhs.baseAllocator_), shared_(rhs.shared_) {
shared_(rhs.shared_)
{
RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0); RAPIDJSON_NOEXCEPT_ASSERT(shared_->refcount > 0);
++shared_->refcount; ++shared_->refcount;
} }
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) RAPIDJSON_NOEXCEPT {
{
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
++rhs.shared_->refcount; ++rhs.shared_->refcount;
this->~MemoryPoolAllocator(); this->~MemoryPoolAllocator();
@ -232,16 +222,13 @@ public:
} }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT : MemoryPoolAllocator(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT : chunk_capacity_(rhs.chunk_capacity_),
chunk_capacity_(rhs.chunk_capacity_), baseAllocator_(rhs.baseAllocator_),
baseAllocator_(rhs.baseAllocator_), shared_(rhs.shared_) {
shared_(rhs.shared_)
{
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
rhs.shared_ = 0; rhs.shared_ = 0;
} }
MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT MemoryPoolAllocator& operator=(MemoryPoolAllocator&& rhs) RAPIDJSON_NOEXCEPT {
{
RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0); RAPIDJSON_NOEXCEPT_ASSERT(rhs.shared_->refcount > 0);
this->~MemoryPoolAllocator(); this->~MemoryPoolAllocator();
baseAllocator_ = rhs.baseAllocator_; baseAllocator_ = rhs.baseAllocator_;
@ -265,7 +252,7 @@ public:
return; return;
} }
Clear(); Clear();
BaseAllocator *a = shared_->ownBaseAllocator; BaseAllocator* a = shared_->ownBaseAllocator;
if (shared_->ownBuffer) { if (shared_->ownBuffer) {
baseAllocator_->Free(shared_); baseAllocator_->Free(shared_);
} }
@ -327,7 +314,7 @@ public:
if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
return NULL; return NULL;
void *buffer = GetChunkBuffer(shared_) + shared_->chunkHead->size; void* buffer = GetChunkBuffer(shared_) + shared_->chunkHead->size;
shared_->chunkHead->size += size; shared_->chunkHead->size += size;
return buffer; return buffer;
} }
@ -368,7 +355,7 @@ public:
} }
//! Frees a memory block (concept Allocator) //! Frees a memory block (concept Allocator)
static void Free(void *ptr) RAPIDJSON_NOEXCEPT { (void)ptr; } // Do nothing static void Free(void* ptr) RAPIDJSON_NOEXCEPT { (void)ptr; } // Do nothing
//! Compare (equality) with another MemoryPoolAllocator //! Compare (equality) with another MemoryPoolAllocator
bool operator==(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT { bool operator==(const MemoryPoolAllocator& rhs) const RAPIDJSON_NOEXCEPT {
@ -400,8 +387,7 @@ private:
return false; return false;
} }
static inline void* AlignBuffer(void* buf, size_t &size) static inline void* AlignBuffer(void* buf, size_t& size) {
{
RAPIDJSON_NOEXCEPT_ASSERT(buf != 0); RAPIDJSON_NOEXCEPT_ASSERT(buf != 0);
const uintptr_t mask = sizeof(void*) - 1; const uintptr_t mask = sizeof(void*) - 1;
const uintptr_t ubuf = reinterpret_cast<uintptr_t>(buf); const uintptr_t ubuf = reinterpret_cast<uintptr_t>(buf);
@ -414,38 +400,31 @@ private:
return buf; return buf;
} }
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
SharedData *shared_; //!< The shared data of the allocator SharedData* shared_; //!< The shared data of the allocator
}; };
namespace internal { namespace internal {
template<typename, typename = void> template <typename, typename = void>
struct IsRefCounted : struct IsRefCounted : public FalseType {};
public FalseType template <typename T>
{ }; struct IsRefCounted<T, typename internal::EnableIfCond<T::kRefCounted>::Type> : public TrueType {};
template<typename T>
struct IsRefCounted<T, typename internal::EnableIfCond<T::kRefCounted>::Type> :
public TrueType
{ };
} }
template<typename T, typename A> template <typename T, typename A>
inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n) inline T* Realloc(A& a, T* old_p, size_t old_n, size_t new_n) {
{
RAPIDJSON_NOEXCEPT_ASSERT(old_n <= SIZE_MAX / sizeof(T) && new_n <= SIZE_MAX / sizeof(T)); RAPIDJSON_NOEXCEPT_ASSERT(old_n <= SIZE_MAX / sizeof(T) && new_n <= SIZE_MAX / sizeof(T));
return static_cast<T*>(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T))); return static_cast<T*>(a.Realloc(old_p, old_n * sizeof(T), new_n * sizeof(T)));
} }
template<typename T, typename A> template <typename T, typename A>
inline T *Malloc(A& a, size_t n = 1) inline T* Malloc(A& a, size_t n = 1) {
{
return Realloc<T, A>(a, NULL, 0, n); return Realloc<T, A>(a, NULL, 0, n);
} }
template<typename T, typename A> template <typename T, typename A>
inline void Free(A& a, T *p, size_t n = 1) inline void Free(A& a, T* p, size_t n = 1) {
{
static_cast<void>(Realloc<T, A>(a, p, n, 0)); static_cast<void>(Realloc<T, A>(a, p, n, 0));
} }
@ -455,9 +434,7 @@ RAPIDJSON_DIAG_OFF(effc++) // std::allocator can safely be inherited
#endif #endif
template <typename T, typename BaseAllocator = CrtAllocator> template <typename T, typename BaseAllocator = CrtAllocator>
class StdAllocator : class StdAllocator : public std::allocator<T> {
public std::allocator<T>
{
typedef std::allocator<T> allocator_type; typedef std::allocator<T> allocator_type;
#if RAPIDJSON_HAS_CXX11 #if RAPIDJSON_HAS_CXX11
typedef std::allocator_traits<allocator_type> traits_type; typedef std::allocator_traits<allocator_type> traits_type;
@ -468,27 +445,19 @@ class StdAllocator :
public: public:
typedef BaseAllocator BaseAllocatorType; typedef BaseAllocator BaseAllocatorType;
StdAllocator() RAPIDJSON_NOEXCEPT : StdAllocator() RAPIDJSON_NOEXCEPT : allocator_type(),
allocator_type(), baseAllocator_() {}
baseAllocator_()
{ }
StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : allocator_type(rhs),
allocator_type(rhs), baseAllocator_(rhs.baseAllocator_) {}
baseAllocator_(rhs.baseAllocator_)
{ }
template<typename U> template <typename U>
StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT : StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT : allocator_type(rhs),
allocator_type(rhs), baseAllocator_(rhs.baseAllocator_) {}
baseAllocator_(rhs.baseAllocator_)
{ }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
StdAllocator(StdAllocator&& rhs) RAPIDJSON_NOEXCEPT : StdAllocator(StdAllocator&& rhs) RAPIDJSON_NOEXCEPT : allocator_type(std::move(rhs)),
allocator_type(std::move(rhs)), baseAllocator_(std::move(rhs.baseAllocator_)) {}
baseAllocator_(std::move(rhs.baseAllocator_))
{ }
#endif #endif
#if RAPIDJSON_HAS_CXX11 #if RAPIDJSON_HAS_CXX11
using propagate_on_container_move_assignment = std::true_type; using propagate_on_container_move_assignment = std::true_type;
@ -496,102 +465,85 @@ public:
#endif #endif
/* implicit */ /* implicit */
StdAllocator(const BaseAllocator& allocator) RAPIDJSON_NOEXCEPT : StdAllocator(const BaseAllocator& allocator) RAPIDJSON_NOEXCEPT : allocator_type(),
allocator_type(), baseAllocator_(allocator) {}
baseAllocator_(allocator)
{ }
~StdAllocator() RAPIDJSON_NOEXCEPT ~StdAllocator() RAPIDJSON_NOEXCEPT {}
{ }
template<typename U> template <typename U>
struct rebind { struct rebind {
typedef StdAllocator<U, BaseAllocator> other; typedef StdAllocator<U, BaseAllocator> other;
}; };
typedef typename traits_type::size_type size_type; typedef typename traits_type::size_type size_type;
typedef typename traits_type::difference_type difference_type; typedef typename traits_type::difference_type difference_type;
typedef typename traits_type::value_type value_type; typedef typename traits_type::value_type value_type;
typedef typename traits_type::pointer pointer; typedef typename traits_type::pointer pointer;
typedef typename traits_type::const_pointer const_pointer; typedef typename traits_type::const_pointer const_pointer;
#if RAPIDJSON_HAS_CXX11 #if RAPIDJSON_HAS_CXX11
typedef typename std::add_lvalue_reference<value_type>::type &reference; typedef typename std::add_lvalue_reference<value_type>::type& reference;
typedef typename std::add_lvalue_reference<typename std::add_const<value_type>::type>::type &const_reference; typedef typename std::add_lvalue_reference<typename std::add_const<value_type>::type>::type& const_reference;
pointer address(reference r) const RAPIDJSON_NOEXCEPT pointer address(reference r) const RAPIDJSON_NOEXCEPT {
{
return std::addressof(r); return std::addressof(r);
} }
const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT {
{
return std::addressof(r); return std::addressof(r);
} }
size_type max_size() const RAPIDJSON_NOEXCEPT size_type max_size() const RAPIDJSON_NOEXCEPT {
{
return traits_type::max_size(*this); return traits_type::max_size(*this);
} }
template <typename ...Args> template <typename... Args>
void construct(pointer p, Args&&... args) void construct(pointer p, Args&&... args) {
{
traits_type::construct(*this, p, std::forward<Args>(args)...); traits_type::construct(*this, p, std::forward<Args>(args)...);
} }
void destroy(pointer p) void destroy(pointer p) {
{
traits_type::destroy(*this, p); traits_type::destroy(*this, p);
} }
#else // !RAPIDJSON_HAS_CXX11 #else // !RAPIDJSON_HAS_CXX11
typedef typename allocator_type::reference reference; typedef typename allocator_type::reference reference;
typedef typename allocator_type::const_reference const_reference; typedef typename allocator_type::const_reference const_reference;
pointer address(reference r) const RAPIDJSON_NOEXCEPT pointer address(reference r) const RAPIDJSON_NOEXCEPT {
{
return allocator_type::address(r); return allocator_type::address(r);
} }
const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT const_pointer address(const_reference r) const RAPIDJSON_NOEXCEPT {
{
return allocator_type::address(r); return allocator_type::address(r);
} }
size_type max_size() const RAPIDJSON_NOEXCEPT size_type max_size() const RAPIDJSON_NOEXCEPT {
{
return allocator_type::max_size(); return allocator_type::max_size();
} }
void construct(pointer p, const_reference r) void construct(pointer p, const_reference r) {
{
allocator_type::construct(p, r); allocator_type::construct(p, r);
} }
void destroy(pointer p) void destroy(pointer p) {
{
allocator_type::destroy(p); allocator_type::destroy(p);
} }
#endif // !RAPIDJSON_HAS_CXX11 #endif // !RAPIDJSON_HAS_CXX11
template <typename U> template <typename U>
U* allocate(size_type n = 1, const void* = 0) U* allocate(size_type n = 1, const void* = 0) {
{
return RAPIDJSON_NAMESPACE::Malloc<U>(baseAllocator_, n); return RAPIDJSON_NAMESPACE::Malloc<U>(baseAllocator_, n);
} }
template <typename U> template <typename U>
void deallocate(U* p, size_type n = 1) void deallocate(U* p, size_type n = 1) {
{
RAPIDJSON_NAMESPACE::Free<U>(baseAllocator_, p, n); RAPIDJSON_NAMESPACE::Free<U>(baseAllocator_, p, n);
} }
pointer allocate(size_type n = 1, const void* = 0) pointer allocate(size_type n = 1, const void* = 0) {
{
return allocate<value_type>(n); return allocate<value_type>(n);
} }
void deallocate(pointer p, size_type n = 1) void deallocate(pointer p, size_type n = 1) {
{
deallocate<value_type>(p, n); deallocate<value_type>(p, n);
} }
@ -599,30 +551,25 @@ public:
using is_always_equal = std::is_empty<BaseAllocator>; using is_always_equal = std::is_empty<BaseAllocator>;
#endif #endif
template<typename U> template <typename U>
bool operator==(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT bool operator==(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT {
{
return baseAllocator_ == rhs.baseAllocator_; return baseAllocator_ == rhs.baseAllocator_;
} }
template<typename U> template <typename U>
bool operator!=(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT bool operator!=(const StdAllocator<U, BaseAllocator>& rhs) const RAPIDJSON_NOEXCEPT {
{
return !operator==(rhs); return !operator==(rhs);
} }
//! rapidjson Allocator concept //! rapidjson Allocator concept
static const bool kNeedFree = BaseAllocator::kNeedFree; static const bool kNeedFree = BaseAllocator::kNeedFree;
static const bool kRefCounted = internal::IsRefCounted<BaseAllocator>::Value; static const bool kRefCounted = internal::IsRefCounted<BaseAllocator>::Value;
void* Malloc(size_t size) void* Malloc(size_t size) {
{
return baseAllocator_.Malloc(size); return baseAllocator_.Malloc(size);
} }
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
{
return baseAllocator_.Realloc(originalPtr, originalSize, newSize); return baseAllocator_.Realloc(originalPtr, originalSize, newSize);
} }
static void Free(void *ptr) RAPIDJSON_NOEXCEPT static void Free(void* ptr) RAPIDJSON_NOEXCEPT {
{
BaseAllocator::Free(ptr); BaseAllocator::Free(ptr);
} }
@ -635,40 +582,29 @@ private:
#if !RAPIDJSON_HAS_CXX17 // std::allocator<void> deprecated in C++17 #if !RAPIDJSON_HAS_CXX17 // std::allocator<void> deprecated in C++17
template <typename BaseAllocator> template <typename BaseAllocator>
class StdAllocator<void, BaseAllocator> : class StdAllocator<void, BaseAllocator> : public std::allocator<void> {
public std::allocator<void>
{
typedef std::allocator<void> allocator_type; typedef std::allocator<void> allocator_type;
public: public:
typedef BaseAllocator BaseAllocatorType; typedef BaseAllocator BaseAllocatorType;
StdAllocator() RAPIDJSON_NOEXCEPT : StdAllocator() RAPIDJSON_NOEXCEPT : allocator_type(),
allocator_type(), baseAllocator_() {}
baseAllocator_()
{ }
StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : StdAllocator(const StdAllocator& rhs) RAPIDJSON_NOEXCEPT : allocator_type(rhs),
allocator_type(rhs), baseAllocator_(rhs.baseAllocator_) {}
baseAllocator_(rhs.baseAllocator_)
{ }
template<typename U> template <typename U>
StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT : StdAllocator(const StdAllocator<U, BaseAllocator>& rhs) RAPIDJSON_NOEXCEPT : allocator_type(rhs),
allocator_type(rhs), baseAllocator_(rhs.baseAllocator_) {}
baseAllocator_(rhs.baseAllocator_)
{ }
/* implicit */ /* implicit */
StdAllocator(const BaseAllocator& allocator) RAPIDJSON_NOEXCEPT : StdAllocator(const BaseAllocator& allocator) RAPIDJSON_NOEXCEPT : allocator_type(),
allocator_type(), baseAllocator_(allocator) {}
baseAllocator_(allocator)
{ }
~StdAllocator() RAPIDJSON_NOEXCEPT ~StdAllocator() RAPIDJSON_NOEXCEPT {}
{ }
template<typename U> template <typename U>
struct rebind { struct rebind {
typedef StdAllocator<U, BaseAllocator> other; typedef StdAllocator<U, BaseAllocator> other;
}; };

View File

@ -24,8 +24,8 @@ RAPIDJSON_DIAG_OFF(effc++)
#if defined(_MSC_VER) && _MSC_VER <= 1800 #if defined(_MSC_VER) && _MSC_VER <= 1800
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4702) // unreachable code RAPIDJSON_DIAG_OFF(4702) // unreachable code
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -35,22 +35,22 @@ RAPIDJSON_NAMESPACE_BEGIN
/*! /*!
\tparam InputStream Any stream that implements Stream Concept \tparam InputStream Any stream that implements Stream Concept
*/ */
template <typename InputStream, typename Encoding = UTF8<> > template <typename InputStream, typename Encoding = UTF8<>>
class CursorStreamWrapper : public GenericStreamWrapper<InputStream, Encoding> { class CursorStreamWrapper : public GenericStreamWrapper<InputStream, Encoding> {
public: public:
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
CursorStreamWrapper(InputStream& is): CursorStreamWrapper(InputStream& is) : GenericStreamWrapper<InputStream, Encoding>(is), line_(1), col_(0) {}
GenericStreamWrapper<InputStream, Encoding>(is), line_(1), col_(0) {}
// counting line and column number // counting line and column number
Ch Take() { Ch Take() {
Ch ch = this->is_.Take(); Ch ch = this->is_.Take();
if(ch == '\n') { if (ch == '\n') {
line_ ++; line_++;
col_ = 0; col_ = 0;
} else { }
col_ ++; else {
col_++;
} }
return ch; return ch;
} }
@ -61,8 +61,8 @@ public:
size_t GetColumn() const { return col_; } size_t GetColumn() const { return col_; }
private: private:
size_t line_; //!< Current Line size_t line_; //!< Current Line
size_t col_; //!< Current Column size_t col_; //!< Current Column
}; };
#if defined(_MSC_VER) && _MSC_VER <= 1800 #if defined(_MSC_VER) && _MSC_VER <= 1800

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ENCODEDSTREAM_H_ #ifndef RAPIDJSON_ENCODEDSTREAM_H_
@ -38,22 +38,33 @@ RAPIDJSON_NAMESPACE_BEGIN
template <typename Encoding, typename InputByteStream> template <typename Encoding, typename InputByteStream>
class EncodedInputStream { class EncodedInputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
public: public:
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
EncodedInputStream(InputByteStream& is) : is_(is) { EncodedInputStream(InputByteStream& is) : is_(is) {
current_ = Encoding::TakeBOM(is_); current_ = Encoding::TakeBOM(is_);
} }
Ch Peek() const { return current_; } Ch Peek() const { return current_; }
Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } Ch Take() {
Ch c = current_;
current_ = Encoding::Take(is_);
return c;
}
size_t Tell() const { return is_.Tell(); } size_t Tell() const { return is_.Tell(); }
// Not implemented // Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); } void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() {
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } RAPIDJSON_ASSERT(false);
return 0;
}
size_t PutEnd(Ch*) {
RAPIDJSON_ASSERT(false);
return 0;
}
private: private:
EncodedInputStream(const EncodedInputStream&); EncodedInputStream(const EncodedInputStream&);
@ -80,7 +91,7 @@ public:
// Not implemented // Not implemented
void Put(Ch) {} void Put(Ch) {}
void Flush() {} void Flush() {}
Ch* PutBegin() { return 0; } Ch* PutBegin() { return 0; }
size_t PutEnd(Ch*) { return 0; } size_t PutEnd(Ch*) { return 0; }
@ -99,23 +110,39 @@ private:
template <typename Encoding, typename OutputByteStream> template <typename Encoding, typename OutputByteStream>
class EncodedOutputStream { class EncodedOutputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
public: public:
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
if (putBOM) if (putBOM)
Encoding::PutBOM(os_); Encoding::PutBOM(os_);
} }
void Put(Ch c) { Encoding::Put(os_, c); } void Put(Ch c) { Encoding::Put(os_, c); }
void Flush() { os_.Flush(); } void Flush() { os_.Flush(); }
// Not implemented // Not implemented
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} Ch Peek() const {
Ch Take() { RAPIDJSON_ASSERT(false); return 0;} RAPIDJSON_ASSERT(false);
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } return 0;
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } Ch Take() {
RAPIDJSON_ASSERT(false);
return 0;
}
size_t Tell() const {
RAPIDJSON_ASSERT(false);
return 0;
}
Ch* PutBegin() {
RAPIDJSON_ASSERT(false);
return 0;
}
size_t PutEnd(Ch*) {
RAPIDJSON_ASSERT(false);
return 0;
}
private: private:
EncodedOutputStream(const EncodedOutputStream&); EncodedOutputStream(const EncodedOutputStream&);
@ -134,6 +161,7 @@ private:
template <typename CharType, typename InputByteStream> template <typename CharType, typename InputByteStream>
class AutoUTFInputStream { class AutoUTFInputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
public: public:
typedef CharType Ch; typedef CharType Ch;
@ -143,7 +171,7 @@ public:
\param type UTF encoding type if it is not detected from the stream. \param type UTF encoding type if it is not detected from the stream.
*/ */
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
DetectType(); DetectType();
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
takeFunc_ = f[type_]; takeFunc_ = f[type_];
@ -154,14 +182,24 @@ public:
bool HasBOM() const { return hasBOM_; } bool HasBOM() const { return hasBOM_; }
Ch Peek() const { return current_; } Ch Peek() const { return current_; }
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } Ch Take() {
Ch c = current_;
current_ = takeFunc_(*is_);
return c;
}
size_t Tell() const { return is_->Tell(); } size_t Tell() const { return is_->Tell(); }
// Not implemented // Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); } void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() {
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } RAPIDJSON_ASSERT(false);
return 0;
}
size_t PutEnd(Ch*) {
RAPIDJSON_ASSERT(false);
return 0;
}
private: private:
AutoUTFInputStream(const AutoUTFInputStream&); AutoUTFInputStream(const AutoUTFInputStream&);
@ -176,17 +214,47 @@ private:
// FF FE UTF-16LE // FF FE UTF-16LE
// EF BB BF UTF-8 // EF BB BF UTF-8
const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4()); const unsigned char* c = reinterpret_cast<const unsigned char*>(is_->Peek4());
if (!c) if (!c)
return; return;
unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
hasBOM_ = false; hasBOM_ = false;
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } if (bom == 0xFFFE0000) {
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } type_ = kUTF32BE;
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } hasBOM_ = true;
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } is_->Take();
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } is_->Take();
is_->Take();
is_->Take();
}
else if (bom == 0x0000FEFF) {
type_ = kUTF32LE;
hasBOM_ = true;
is_->Take();
is_->Take();
is_->Take();
is_->Take();
}
else if ((bom & 0xFFFF) == 0xFFFE) {
type_ = kUTF16BE;
hasBOM_ = true;
is_->Take();
is_->Take();
}
else if ((bom & 0xFFFF) == 0xFEFF) {
type_ = kUTF16LE;
hasBOM_ = true;
is_->Take();
is_->Take();
}
else if ((bom & 0xFFFFFF) == 0xBFBBEF) {
type_ = kUTF8;
hasBOM_ = true;
is_->Take();
is_->Take();
is_->Take();
}
// RFC 4627: Section 3 // RFC 4627: Section 3
// "Since the first two characters of a JSON text will always be ASCII // "Since the first two characters of a JSON text will always be ASCII
@ -202,12 +270,23 @@ private:
if (!hasBOM_) { if (!hasBOM_) {
int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
switch (pattern) { switch (pattern) {
case 0x08: type_ = kUTF32BE; break; case 0x08:
case 0x0A: type_ = kUTF16BE; break; type_ = kUTF32BE;
case 0x01: type_ = kUTF32LE; break; break;
case 0x05: type_ = kUTF16LE; break; case 0x0A:
case 0x0F: type_ = kUTF8; break; type_ = kUTF16BE;
default: break; // Use type defined by user. break;
case 0x01:
type_ = kUTF32LE;
break;
case 0x05:
type_ = kUTF16LE;
break;
case 0x0F:
type_ = kUTF8;
break;
default:
break; // Use type defined by user.
} }
} }
@ -232,6 +311,7 @@ private:
template <typename CharType, typename OutputByteStream> template <typename CharType, typename OutputByteStream>
class AutoUTFOutputStream { class AutoUTFOutputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
public: public:
typedef CharType Ch; typedef CharType Ch;
@ -258,20 +338,35 @@ public:
UTFType GetType() const { return type_; } UTFType GetType() const { return type_; }
void Put(Ch c) { putFunc_(*os_, c); } void Put(Ch c) { putFunc_(*os_, c); }
void Flush() { os_->Flush(); } void Flush() { os_->Flush(); }
// Not implemented // Not implemented
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} Ch Peek() const {
Ch Take() { RAPIDJSON_ASSERT(false); return 0;} RAPIDJSON_ASSERT(false);
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } return 0;
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } Ch Take() {
RAPIDJSON_ASSERT(false);
return 0;
}
size_t Tell() const {
RAPIDJSON_ASSERT(false);
return 0;
}
Ch* PutBegin() {
RAPIDJSON_ASSERT(false);
return 0;
}
size_t PutEnd(Ch*) {
RAPIDJSON_ASSERT(false);
return 0;
}
private: private:
AutoUTFOutputStream(const AutoUTFOutputStream&); AutoUTFOutputStream(const AutoUTFOutputStream&);
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
void PutBOM() { void PutBOM() {
typedef void (*PutBOMFunc)(OutputByteStream&); typedef void (*PutBOMFunc)(OutputByteStream&);
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
f[type_](*os_); f[type_](*os_);

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ENCODINGS_H_ #ifndef RAPIDJSON_ENCODINGS_H_
@ -20,7 +20,7 @@
#if defined(_MSC_VER) && !defined(__clang__) #if defined(_MSC_VER) && !defined(__clang__)
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
RAPIDJSON_DIAG_OFF(4702) // unreachable code RAPIDJSON_DIAG_OFF(4702) // unreachable code
#elif defined(__GNUC__) #elif defined(__GNUC__)
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
@ -92,15 +92,15 @@ concept Encoding {
\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
\note implements Encoding concept \note implements Encoding concept
*/ */
template<typename CharType = char> template <typename CharType = char>
struct UTF8 { struct UTF8 {
typedef CharType Ch; typedef CharType Ch;
enum { supportUnicode = 1 }; enum { supportUnicode = 1 };
template<typename OutputStream> template <typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) { static void Encode(OutputStream& os, unsigned codepoint) {
if (codepoint <= 0x7F) if (codepoint <= 0x7F)
os.Put(static_cast<Ch>(codepoint & 0xFF)); os.Put(static_cast<Ch>(codepoint & 0xFF));
else if (codepoint <= 0x7FF) { else if (codepoint <= 0x7FF) {
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF))); os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
@ -120,9 +120,9 @@ struct UTF8 {
} }
} }
template<typename OutputStream> template <typename OutputStream>
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
if (codepoint <= 0x7F) if (codepoint <= 0x7F)
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF)); PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
else if (codepoint <= 0x7FF) { else if (codepoint <= 0x7FF) {
PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF))); PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
@ -144,9 +144,13 @@ struct UTF8 {
template <typename InputStream> template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) { static bool Decode(InputStream& is, unsigned* codepoint) {
#define RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu) #define RAPIDJSON_COPY() \
c = is.Take(); \
*codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0) #define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) #define RAPIDJSON_TAIL() \
RAPIDJSON_COPY(); \
RAPIDJSON_TRANS(0x70)
typename InputStream::Ch c = is.Take(); typename InputStream::Ch c = is.Take();
if (!(c & 0x80)) { if (!(c & 0x80)) {
*codepoint = static_cast<unsigned char>(c); *codepoint = static_cast<unsigned char>(c);
@ -156,19 +160,48 @@ struct UTF8 {
unsigned char type = GetRange(static_cast<unsigned char>(c)); unsigned char type = GetRange(static_cast<unsigned char>(c));
if (type >= 32) { if (type >= 32) {
*codepoint = 0; *codepoint = 0;
} else { }
else {
*codepoint = (0xFFu >> type) & static_cast<unsigned char>(c); *codepoint = (0xFFu >> type) & static_cast<unsigned char>(c);
} }
bool result = true; bool result = true;
switch (type) { switch (type) {
case 2: RAPIDJSON_TAIL(); return result; case 2:
case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; RAPIDJSON_TAIL();
case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result; return result;
case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; case 3:
case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; RAPIDJSON_TAIL();
case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result; RAPIDJSON_TAIL();
case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; return result;
default: return false; case 4:
RAPIDJSON_COPY();
RAPIDJSON_TRANS(0x50);
RAPIDJSON_TAIL();
return result;
case 5:
RAPIDJSON_COPY();
RAPIDJSON_TRANS(0x10);
RAPIDJSON_TAIL();
RAPIDJSON_TAIL();
return result;
case 6:
RAPIDJSON_TAIL();
RAPIDJSON_TAIL();
RAPIDJSON_TAIL();
return result;
case 10:
RAPIDJSON_COPY();
RAPIDJSON_TRANS(0x20);
RAPIDJSON_TAIL();
return result;
case 11:
RAPIDJSON_COPY();
RAPIDJSON_TRANS(0x60);
RAPIDJSON_TAIL();
RAPIDJSON_TAIL();
return result;
default:
return false;
} }
#undef RAPIDJSON_COPY #undef RAPIDJSON_COPY
#undef RAPIDJSON_TRANS #undef RAPIDJSON_TRANS
@ -177,9 +210,11 @@ struct UTF8 {
template <typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) { static bool Validate(InputStream& is, OutputStream& os) {
#define RAPIDJSON_COPY() os.Put(c = is.Take()) #define RAPIDJSON_COPY() os.Put(c = is.Take())
#define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0) #define RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
#define RAPIDJSON_TAIL() RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x70) #define RAPIDJSON_TAIL() \
RAPIDJSON_COPY(); \
RAPIDJSON_TRANS(0x70)
Ch c; Ch c;
RAPIDJSON_COPY(); RAPIDJSON_COPY();
if (!(c & 0x80)) if (!(c & 0x80))
@ -187,14 +222,42 @@ struct UTF8 {
bool result = true; bool result = true;
switch (GetRange(static_cast<unsigned char>(c))) { switch (GetRange(static_cast<unsigned char>(c))) {
case 2: RAPIDJSON_TAIL(); return result; case 2:
case 3: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; RAPIDJSON_TAIL();
case 4: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x50); RAPIDJSON_TAIL(); return result; return result;
case 5: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x10); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; case 3:
case 6: RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; RAPIDJSON_TAIL();
case 10: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x20); RAPIDJSON_TAIL(); return result; RAPIDJSON_TAIL();
case 11: RAPIDJSON_COPY(); RAPIDJSON_TRANS(0x60); RAPIDJSON_TAIL(); RAPIDJSON_TAIL(); return result; return result;
default: return false; case 4:
RAPIDJSON_COPY();
RAPIDJSON_TRANS(0x50);
RAPIDJSON_TAIL();
return result;
case 5:
RAPIDJSON_COPY();
RAPIDJSON_TRANS(0x10);
RAPIDJSON_TAIL();
RAPIDJSON_TAIL();
return result;
case 6:
RAPIDJSON_TAIL();
RAPIDJSON_TAIL();
RAPIDJSON_TAIL();
return result;
case 10:
RAPIDJSON_COPY();
RAPIDJSON_TRANS(0x20);
RAPIDJSON_TAIL();
return result;
case 11:
RAPIDJSON_COPY();
RAPIDJSON_TRANS(0x60);
RAPIDJSON_TAIL();
RAPIDJSON_TAIL();
return result;
default:
return false;
} }
#undef RAPIDJSON_COPY #undef RAPIDJSON_COPY
#undef RAPIDJSON_TRANS #undef RAPIDJSON_TRANS
@ -205,16 +268,262 @@ struct UTF8 {
// Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
// With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
static const unsigned char type[] = { static const unsigned char type[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 0,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 0,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0,
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 0,
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0x10,
0x10,
0x10,
0x10,
0x10,
0x10,
0x10,
0x10,
0x10,
0x10,
0x10,
0x10,
0x10,
0x10,
0x10,
0x10,
0x40,
0x40,
0x40,
0x40,
0x40,
0x40,
0x40,
0x40,
0x40,
0x40,
0x40,
0x40,
0x40,
0x40,
0x40,
0x40,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
0x20,
8,
8,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
10,
3,
3,
3,
3,
3,
3,
3,
3,
3,
3,
3,
3,
4,
3,
3,
11,
6,
6,
6,
5,
8,
8,
8,
8,
8,
8,
8,
8,
8,
8,
8,
}; };
return type[c]; return type[c];
} }
@ -265,18 +574,18 @@ struct UTF8 {
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
For streaming, use UTF16LE and UTF16BE, which handle endianness. For streaming, use UTF16LE and UTF16BE, which handle endianness.
*/ */
template<typename CharType = wchar_t> template <typename CharType = wchar_t>
struct UTF16 { struct UTF16 {
typedef CharType Ch; typedef CharType Ch;
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
enum { supportUnicode = 1 }; enum { supportUnicode = 1 };
template<typename OutputStream> template <typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) { static void Encode(OutputStream& os, unsigned codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
if (codepoint <= 0xFFFF) { if (codepoint <= 0xFFFF) {
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
os.Put(static_cast<typename OutputStream::Ch>(codepoint)); os.Put(static_cast<typename OutputStream::Ch>(codepoint));
} }
else { else {
@ -288,11 +597,11 @@ struct UTF16 {
} }
template<typename OutputStream> template <typename OutputStream>
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
if (codepoint <= 0xFFFF) { if (codepoint <= 0xFFFF) {
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint)); PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
} }
else { else {
@ -338,7 +647,7 @@ struct UTF16 {
}; };
//! UTF-16 little endian encoding. //! UTF-16 little endian encoding.
template<typename CharType = wchar_t> template <typename CharType = wchar_t>
struct UTF16LE : UTF16<CharType> { struct UTF16LE : UTF16<CharType> {
template <typename InputByteStream> template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream& is) {
@ -371,7 +680,7 @@ struct UTF16LE : UTF16<CharType> {
}; };
//! UTF-16 big endian encoding. //! UTF-16 big endian encoding.
template<typename CharType = wchar_t> template <typename CharType = wchar_t>
struct UTF16BE : UTF16<CharType> { struct UTF16BE : UTF16<CharType> {
template <typename InputByteStream> template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream& is) {
@ -406,7 +715,7 @@ struct UTF16BE : UTF16<CharType> {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// UTF32 // UTF32
//! UTF-32 encoding. //! UTF-32 encoding.
/*! http://en.wikipedia.org/wiki/UTF-32 /*! http://en.wikipedia.org/wiki/UTF-32
\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
\note implements Encoding concept \note implements Encoding concept
@ -414,21 +723,21 @@ struct UTF16BE : UTF16<CharType> {
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
For streaming, use UTF32LE and UTF32BE, which handle endianness. For streaming, use UTF32LE and UTF32BE, which handle endianness.
*/ */
template<typename CharType = unsigned> template <typename CharType = unsigned>
struct UTF32 { struct UTF32 {
typedef CharType Ch; typedef CharType Ch;
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
enum { supportUnicode = 1 }; enum { supportUnicode = 1 };
template<typename OutputStream> template <typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) { static void Encode(OutputStream& os, unsigned codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
os.Put(codepoint); os.Put(codepoint);
} }
template<typename OutputStream> template <typename OutputStream>
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
@ -453,7 +762,7 @@ struct UTF32 {
}; };
//! UTF-32 little endian enocoding. //! UTF-32 little endian enocoding.
template<typename CharType = unsigned> template <typename CharType = unsigned>
struct UTF32LE : UTF32<CharType> { struct UTF32LE : UTF32<CharType> {
template <typename InputByteStream> template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream& is) {
@ -492,13 +801,13 @@ struct UTF32LE : UTF32<CharType> {
}; };
//! UTF-32 big endian encoding. //! UTF-32 big endian encoding.
template<typename CharType = unsigned> template <typename CharType = unsigned>
struct UTF32BE : UTF32<CharType> { struct UTF32BE : UTF32<CharType> {
template <typename InputByteStream> template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) { static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is); CharType c = Take(is);
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c; return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
} }
template <typename InputByteStream> template <typename InputByteStream>
@ -538,19 +847,19 @@ struct UTF32BE : UTF32<CharType> {
\tparam CharType Code unit for storing 7-bit ASCII data. Default is char. \tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
\note implements Encoding concept \note implements Encoding concept
*/ */
template<typename CharType = char> template <typename CharType = char>
struct ASCII { struct ASCII {
typedef CharType Ch; typedef CharType Ch;
enum { supportUnicode = 0 }; enum { supportUnicode = 0 };
template<typename OutputStream> template <typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) { static void Encode(OutputStream& os, unsigned codepoint) {
RAPIDJSON_ASSERT(codepoint <= 0x7F); RAPIDJSON_ASSERT(codepoint <= 0x7F);
os.Put(static_cast<Ch>(codepoint & 0xFF)); os.Put(static_cast<Ch>(codepoint & 0xFF));
} }
template<typename OutputStream> template <typename OutputStream>
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
RAPIDJSON_ASSERT(codepoint <= 0x7F); RAPIDJSON_ASSERT(codepoint <= 0x7F);
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF)); PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
@ -601,17 +910,17 @@ struct ASCII {
//! Runtime-specified UTF encoding type of a stream. //! Runtime-specified UTF encoding type of a stream.
enum UTFType { enum UTFType {
kUTF8 = 0, //!< UTF-8. kUTF8 = 0, //!< UTF-8.
kUTF16LE = 1, //!< UTF-16 little endian. kUTF16LE = 1, //!< UTF-16 little endian.
kUTF16BE = 2, //!< UTF-16 big endian. kUTF16BE = 2, //!< UTF-16 big endian.
kUTF32LE = 3, //!< UTF-32 little endian. kUTF32LE = 3, //!< UTF-32 little endian.
kUTF32BE = 4 //!< UTF-32 big endian. kUTF32BE = 4 //!< UTF-32 big endian.
}; };
//! Dynamically select encoding according to stream's runtime-specified UTF encoding type. //! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType(). /*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
*/ */
template<typename CharType> template <typename CharType>
struct AutoUTF { struct AutoUTF {
typedef CharType Ch; typedef CharType Ch;
@ -619,14 +928,14 @@ struct AutoUTF {
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
template<typename OutputStream> template <typename OutputStream>
static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) { static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) {
typedef void (*EncodeFunc)(OutputStream&, unsigned); typedef void (*EncodeFunc)(OutputStream&, unsigned);
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
(*f[os.GetType()])(os, codepoint); (*f[os.GetType()])(os, codepoint);
} }
template<typename OutputStream> template <typename OutputStream>
static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) { static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
typedef void (*EncodeFunc)(OutputStream&, unsigned); typedef void (*EncodeFunc)(OutputStream&, unsigned);
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
@ -654,10 +963,10 @@ struct AutoUTF {
// Transcoder // Transcoder
//! Encoding conversion. //! Encoding conversion.
template<typename SourceEncoding, typename TargetEncoding> template <typename SourceEncoding, typename TargetEncoding>
struct Transcoder { struct Transcoder {
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
template<typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
unsigned codepoint; unsigned codepoint;
if (!SourceEncoding::Decode(is, &codepoint)) if (!SourceEncoding::Decode(is, &codepoint))
@ -666,7 +975,7 @@ struct Transcoder {
return true; return true;
} }
template<typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
unsigned codepoint; unsigned codepoint;
if (!SourceEncoding::Decode(is, &codepoint)) if (!SourceEncoding::Decode(is, &codepoint))
@ -676,34 +985,34 @@ struct Transcoder {
} }
//! Validate one Unicode codepoint from an encoded stream. //! Validate one Unicode codepoint from an encoded stream.
template<typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
return Transcode(is, os); // Since source/target encoding is different, must transcode. return Transcode(is, os); // Since source/target encoding is different, must transcode.
} }
}; };
// Forward declaration. // Forward declaration.
template<typename Stream> template <typename Stream>
inline void PutUnsafe(Stream& stream, typename Stream::Ch c); inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
//! Specialization of Transcoder with same source and target encoding. //! Specialization of Transcoder with same source and target encoding.
template<typename Encoding> template <typename Encoding>
struct Transcoder<Encoding, Encoding> { struct Transcoder<Encoding, Encoding> {
template<typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
return true; return true;
} }
template<typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class.
return true; return true;
} }
template<typename InputStream, typename OutputStream> template <typename InputStream, typename OutputStream>
static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
return Encoding::Validate(is, os); // source/target encoding are the same return Encoding::Validate(is, os); // source/target encoding are the same
} }
}; };

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ERROR_EN_H_ #ifndef RAPIDJSON_ERROR_EN_H_
@ -19,8 +19,8 @@
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(switch - enum)
RAPIDJSON_DIAG_OFF(covered-switch-default) RAPIDJSON_DIAG_OFF(covered - switch - default)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -35,33 +35,52 @@ RAPIDJSON_NAMESPACE_BEGIN
*/ */
inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
switch (parseErrorCode) { switch (parseErrorCode) {
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); case kParseErrorNone:
return RAPIDJSON_ERROR_STRING("No error.");
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); case kParseErrorDocumentEmpty:
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); return RAPIDJSON_ERROR_STRING("The document is empty.");
case kParseErrorDocumentRootNotSingular:
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); case kParseErrorValueInvalid:
case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); return RAPIDJSON_ERROR_STRING("Invalid value.");
case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); case kParseErrorObjectMissName:
case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); case kParseErrorObjectMissColon:
return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
case kParseErrorObjectMissCommaOrCurlyBracket:
return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); case kParseErrorArrayMissCommaOrSquareBracket:
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
default: return RAPIDJSON_ERROR_STRING("Unknown error."); case kParseErrorStringUnicodeEscapeInvalidHex:
return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
case kParseErrorStringUnicodeSurrogateInvalid:
return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
case kParseErrorStringEscapeInvalid:
return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
case kParseErrorStringMissQuotationMark:
return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
case kParseErrorStringInvalidEncoding:
return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
case kParseErrorNumberTooBig:
return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
case kParseErrorNumberMissFraction:
return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
case kParseErrorNumberMissExponent:
return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
case kParseErrorTermination:
return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
case kParseErrorUnspecificSyntaxError:
return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
default:
return RAPIDJSON_ERROR_STRING("Unknown error.");
} }
} }
@ -75,41 +94,69 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro
*/ */
inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode validateErrorCode) { inline const RAPIDJSON_ERROR_CHARTYPE* GetValidateError_En(ValidateErrorCode validateErrorCode) {
switch (validateErrorCode) { switch (validateErrorCode) {
case kValidateErrors: return RAPIDJSON_ERROR_STRING("One or more validation errors have occurred"); case kValidateErrors:
case kValidateErrorNone: return RAPIDJSON_ERROR_STRING("No error."); return RAPIDJSON_ERROR_STRING("One or more validation errors have occurred");
case kValidateErrorNone:
return RAPIDJSON_ERROR_STRING("No error.");
case kValidateErrorMultipleOf: return RAPIDJSON_ERROR_STRING("Number '%actual' is not a multiple of the 'multipleOf' value '%expected'."); case kValidateErrorMultipleOf:
case kValidateErrorMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than the 'maximum' value '%expected'."); return RAPIDJSON_ERROR_STRING("Number '%actual' is not a multiple of the 'multipleOf' value '%expected'.");
case kValidateErrorExclusiveMaximum: return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than or equal to the 'exclusiveMaximum' value '%expected'."); case kValidateErrorMaximum:
case kValidateErrorMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than the 'minimum' value '%expected'."); return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than the 'maximum' value '%expected'.");
case kValidateErrorExclusiveMinimum: return RAPIDJSON_ERROR_STRING("Number '%actual' is less than or equal to the 'exclusiveMinimum' value '%expected'."); case kValidateErrorExclusiveMaximum:
return RAPIDJSON_ERROR_STRING("Number '%actual' is greater than or equal to the 'exclusiveMaximum' value '%expected'.");
case kValidateErrorMinimum:
return RAPIDJSON_ERROR_STRING("Number '%actual' is less than the 'minimum' value '%expected'.");
case kValidateErrorExclusiveMinimum:
return RAPIDJSON_ERROR_STRING("Number '%actual' is less than or equal to the 'exclusiveMinimum' value '%expected'.");
case kValidateErrorMaxLength: return RAPIDJSON_ERROR_STRING("String '%actual' is longer than the 'maxLength' value '%expected'."); case kValidateErrorMaxLength:
case kValidateErrorMinLength: return RAPIDJSON_ERROR_STRING("String '%actual' is shorter than the 'minLength' value '%expected'."); return RAPIDJSON_ERROR_STRING("String '%actual' is longer than the 'maxLength' value '%expected'.");
case kValidateErrorPattern: return RAPIDJSON_ERROR_STRING("String '%actual' does not match the 'pattern' regular expression."); case kValidateErrorMinLength:
return RAPIDJSON_ERROR_STRING("String '%actual' is shorter than the 'minLength' value '%expected'.");
case kValidateErrorPattern:
return RAPIDJSON_ERROR_STRING("String '%actual' does not match the 'pattern' regular expression.");
case kValidateErrorMaxItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is longer than the 'maxItems' value '%expected'."); case kValidateErrorMaxItems:
case kValidateErrorMinItems: return RAPIDJSON_ERROR_STRING("Array of length '%actual' is shorter than the 'minItems' value '%expected'."); return RAPIDJSON_ERROR_STRING("Array of length '%actual' is longer than the 'maxItems' value '%expected'.");
case kValidateErrorUniqueItems: return RAPIDJSON_ERROR_STRING("Array has duplicate items at indices '%duplicates' but 'uniqueItems' is true."); case kValidateErrorMinItems:
case kValidateErrorAdditionalItems: return RAPIDJSON_ERROR_STRING("Array has an additional item at index '%disallowed' that is not allowed by the schema."); return RAPIDJSON_ERROR_STRING("Array of length '%actual' is shorter than the 'minItems' value '%expected'.");
case kValidateErrorUniqueItems:
return RAPIDJSON_ERROR_STRING("Array has duplicate items at indices '%duplicates' but 'uniqueItems' is true.");
case kValidateErrorAdditionalItems:
return RAPIDJSON_ERROR_STRING("Array has an additional item at index '%disallowed' that is not allowed by the schema.");
case kValidateErrorMaxProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is more than 'maxProperties' value '%expected'."); case kValidateErrorMaxProperties:
case kValidateErrorMinProperties: return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is less than 'minProperties' value '%expected'."); return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is more than 'maxProperties' value '%expected'.");
case kValidateErrorRequired: return RAPIDJSON_ERROR_STRING("Object is missing the following members required by the schema: '%missing'."); case kValidateErrorMinProperties:
case kValidateErrorAdditionalProperties: return RAPIDJSON_ERROR_STRING("Object has an additional member '%disallowed' that is not allowed by the schema."); return RAPIDJSON_ERROR_STRING("Object has '%actual' members which is less than 'minProperties' value '%expected'.");
case kValidateErrorPatternProperties: return RAPIDJSON_ERROR_STRING("Object has 'patternProperties' that are not allowed by the schema."); case kValidateErrorRequired:
case kValidateErrorDependencies: return RAPIDJSON_ERROR_STRING("Object has missing property or schema dependencies, refer to following errors."); return RAPIDJSON_ERROR_STRING("Object is missing the following members required by the schema: '%missing'.");
case kValidateErrorAdditionalProperties:
return RAPIDJSON_ERROR_STRING("Object has an additional member '%disallowed' that is not allowed by the schema.");
case kValidateErrorPatternProperties:
return RAPIDJSON_ERROR_STRING("Object has 'patternProperties' that are not allowed by the schema.");
case kValidateErrorDependencies:
return RAPIDJSON_ERROR_STRING("Object has missing property or schema dependencies, refer to following errors.");
case kValidateErrorEnum: return RAPIDJSON_ERROR_STRING("Property has a value that is not one of its allowed enumerated values."); case kValidateErrorEnum:
case kValidateErrorType: return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'."); return RAPIDJSON_ERROR_STRING("Property has a value that is not one of its allowed enumerated values.");
case kValidateErrorType:
return RAPIDJSON_ERROR_STRING("Property has a type '%actual' that is not in the following list: '%expected'.");
case kValidateErrorOneOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors."); case kValidateErrorOneOf:
case kValidateErrorOneOfMatch: return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf'."); return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'oneOf', refer to following errors.");
case kValidateErrorAllOf: return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors."); case kValidateErrorOneOfMatch:
case kValidateErrorAnyOf: return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors."); return RAPIDJSON_ERROR_STRING("Property matched more than one of the sub-schemas specified by 'oneOf'.");
case kValidateErrorNot: return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'."); case kValidateErrorAllOf:
return RAPIDJSON_ERROR_STRING("Property did not match all of the sub-schemas specified by 'allOf', refer to following errors.");
case kValidateErrorAnyOf:
return RAPIDJSON_ERROR_STRING("Property did not match any of the sub-schemas specified by 'anyOf', refer to following errors.");
case kValidateErrorNot:
return RAPIDJSON_ERROR_STRING("Property matched the sub-schema specified by 'not'.");
default: return RAPIDJSON_ERROR_STRING("Unknown error."); default:
return RAPIDJSON_ERROR_STRING("Unknown error.");
} }
} }

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ERROR_ERROR_H_ #ifndef RAPIDJSON_ERROR_ERROR_H_
@ -62,31 +62,31 @@ RAPIDJSON_NAMESPACE_BEGIN
\see GenericReader::Parse, GenericReader::GetParseErrorCode \see GenericReader::Parse, GenericReader::GetParseErrorCode
*/ */
enum ParseErrorCode { enum ParseErrorCode {
kParseErrorNone = 0, //!< No error. kParseErrorNone = 0, //!< No error.
kParseErrorDocumentEmpty, //!< The document is empty. kParseErrorDocumentEmpty, //!< The document is empty.
kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
kParseErrorValueInvalid, //!< Invalid value. kParseErrorValueInvalid, //!< Invalid value.
kParseErrorObjectMissName, //!< Missing a name for object member. kParseErrorObjectMissName, //!< Missing a name for object member.
kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
kParseErrorNumberTooBig, //!< Number too big to be stored in double. kParseErrorNumberTooBig, //!< Number too big to be stored in double.
kParseErrorNumberMissFraction, //!< Miss fraction part in number. kParseErrorNumberMissFraction, //!< Miss fraction part in number.
kParseErrorNumberMissExponent, //!< Miss exponent in number. kParseErrorNumberMissExponent, //!< Miss exponent in number.
kParseErrorTermination, //!< Parsing was terminated. kParseErrorTermination, //!< Parsing was terminated.
kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
}; };
//! Result of parsing (wraps ParseErrorCode) //! Result of parsing (wraps ParseErrorCode)
@ -106,6 +106,7 @@ enum ParseErrorCode {
struct ParseResult { struct ParseResult {
//!! Unspecified boolean type //!! Unspecified boolean type
typedef bool (ParseResult::*BooleanType)() const; typedef bool (ParseResult::*BooleanType)() const;
public: public:
//! Default constructor, no error. //! Default constructor, no error.
ParseResult() : code_(kParseErrorNone), offset_(0) {} ParseResult() : code_(kParseErrorNone), offset_(0) {}
@ -124,16 +125,19 @@ public:
bool operator==(const ParseResult& that) const { return code_ == that.code_; } bool operator==(const ParseResult& that) const { return code_ == that.code_; }
bool operator==(ParseErrorCode code) const { return code_ == code; } bool operator==(ParseErrorCode code) const { return code_ == code; }
friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } friend bool operator==(ParseErrorCode code, const ParseResult& err) { return code == err.code_; }
bool operator!=(const ParseResult& that) const { return !(*this == that); } bool operator!=(const ParseResult& that) const { return !(*this == that); }
bool operator!=(ParseErrorCode code) const { return !(*this == code); } bool operator!=(ParseErrorCode code) const { return !(*this == code); }
friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; } friend bool operator!=(ParseErrorCode code, const ParseResult& err) { return err != code; }
//! Reset error code. //! Reset error code.
void Clear() { Set(kParseErrorNone); } void Clear() { Set(kParseErrorNone); }
//! Update error code and offset. //! Update error code and offset.
void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } void Set(ParseErrorCode code, size_t offset = 0) {
code_ = code;
offset_ = offset;
}
private: private:
ParseErrorCode code_; ParseErrorCode code_;
@ -160,39 +164,39 @@ typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
\see GenericSchemaValidator \see GenericSchemaValidator
*/ */
enum ValidateErrorCode { enum ValidateErrorCode {
kValidateErrors = -1, //!< Top level error code when kValidateContinueOnErrorsFlag set. kValidateErrors = -1, //!< Top level error code when kValidateContinueOnErrorsFlag set.
kValidateErrorNone = 0, //!< No error. kValidateErrorNone = 0, //!< No error.
kValidateErrorMultipleOf, //!< Number is not a multiple of the 'multipleOf' value. kValidateErrorMultipleOf, //!< Number is not a multiple of the 'multipleOf' value.
kValidateErrorMaximum, //!< Number is greater than the 'maximum' value. kValidateErrorMaximum, //!< Number is greater than the 'maximum' value.
kValidateErrorExclusiveMaximum, //!< Number is greater than or equal to the 'maximum' value. kValidateErrorExclusiveMaximum, //!< Number is greater than or equal to the 'maximum' value.
kValidateErrorMinimum, //!< Number is less than the 'minimum' value. kValidateErrorMinimum, //!< Number is less than the 'minimum' value.
kValidateErrorExclusiveMinimum, //!< Number is less than or equal to the 'minimum' value. kValidateErrorExclusiveMinimum, //!< Number is less than or equal to the 'minimum' value.
kValidateErrorMaxLength, //!< String is longer than the 'maxLength' value. kValidateErrorMaxLength, //!< String is longer than the 'maxLength' value.
kValidateErrorMinLength, //!< String is longer than the 'maxLength' value. kValidateErrorMinLength, //!< String is longer than the 'maxLength' value.
kValidateErrorPattern, //!< String does not match the 'pattern' regular expression. kValidateErrorPattern, //!< String does not match the 'pattern' regular expression.
kValidateErrorMaxItems, //!< Array is longer than the 'maxItems' value. kValidateErrorMaxItems, //!< Array is longer than the 'maxItems' value.
kValidateErrorMinItems, //!< Array is shorter than the 'minItems' value. kValidateErrorMinItems, //!< Array is shorter than the 'minItems' value.
kValidateErrorUniqueItems, //!< Array has duplicate items but 'uniqueItems' is true. kValidateErrorUniqueItems, //!< Array has duplicate items but 'uniqueItems' is true.
kValidateErrorAdditionalItems, //!< Array has additional items that are not allowed by the schema. kValidateErrorAdditionalItems, //!< Array has additional items that are not allowed by the schema.
kValidateErrorMaxProperties, //!< Object has more members than 'maxProperties' value. kValidateErrorMaxProperties, //!< Object has more members than 'maxProperties' value.
kValidateErrorMinProperties, //!< Object has less members than 'minProperties' value. kValidateErrorMinProperties, //!< Object has less members than 'minProperties' value.
kValidateErrorRequired, //!< Object is missing one or more members required by the schema. kValidateErrorRequired, //!< Object is missing one or more members required by the schema.
kValidateErrorAdditionalProperties, //!< Object has additional members that are not allowed by the schema. kValidateErrorAdditionalProperties, //!< Object has additional members that are not allowed by the schema.
kValidateErrorPatternProperties, //!< See other errors. kValidateErrorPatternProperties, //!< See other errors.
kValidateErrorDependencies, //!< Object has missing property or schema dependencies. kValidateErrorDependencies, //!< Object has missing property or schema dependencies.
kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values kValidateErrorEnum, //!< Property has a value that is not one of its allowed enumerated values
kValidateErrorType, //!< Property has a type that is not allowed by the schema.. kValidateErrorType, //!< Property has a type that is not allowed by the schema..
kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'. kValidateErrorOneOf, //!< Property did not match any of the sub-schemas specified by 'oneOf'.
kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'. kValidateErrorOneOfMatch, //!< Property matched more than one of the sub-schemas specified by 'oneOf'.
kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'. kValidateErrorAllOf, //!< Property did not match all of the sub-schemas specified by 'allOf'.
kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'. kValidateErrorAnyOf, //!< Property did not match any of the sub-schemas specified by 'anyOf'.
kValidateErrorNot //!< Property matched the sub-schema specified by 'not'. kValidateErrorNot //!< Property matched the sub-schema specified by 'not'.
}; };
//! Function pointer type of GetValidateError(). //! Function pointer type of GetValidateError().

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FILEREADSTREAM_H_ #ifndef RAPIDJSON_FILEREADSTREAM_H_
@ -21,8 +21,8 @@
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(unreachable - code)
RAPIDJSON_DIAG_OFF(missing-noreturn) RAPIDJSON_DIAG_OFF(missing - noreturn)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -33,7 +33,7 @@ RAPIDJSON_NAMESPACE_BEGIN
*/ */
class FileReadStream { class FileReadStream {
public: public:
typedef char Ch; //!< Character type (byte). typedef char Ch; //!< Character type (byte).
//! Constructor. //! Constructor.
/*! /*!
@ -41,21 +41,31 @@ public:
\param buffer user-supplied buffer. \param buffer user-supplied buffer.
\param bufferSize size of buffer in bytes. Must >=4 bytes. \param bufferSize size of buffer in bytes. Must >=4 bytes.
*/ */
FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
RAPIDJSON_ASSERT(fp_ != 0); RAPIDJSON_ASSERT(fp_ != 0);
RAPIDJSON_ASSERT(bufferSize >= 4); RAPIDJSON_ASSERT(bufferSize >= 4);
Read(); Read();
} }
Ch Peek() const { return *current_; } Ch Peek() const { return *current_; }
Ch Take() { Ch c = *current_; Read(); return c; } Ch Take() {
Ch c = *current_;
Read();
return c;
}
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); } size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
// Not implemented // Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); } void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() {
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } RAPIDJSON_ASSERT(false);
return 0;
}
size_t PutEnd(Ch*) {
RAPIDJSON_ASSERT(false);
return 0;
}
// For encoding detection only. // For encoding detection only.
const Ch* Peek4() const { const Ch* Peek4() const {
@ -81,12 +91,12 @@ private:
} }
std::FILE* fp_; std::FILE* fp_;
Ch *buffer_; Ch* buffer_;
size_t bufferSize_; size_t bufferSize_;
Ch *bufferLast_; Ch* bufferLast_;
Ch *current_; Ch* current_;
size_t readCount_; size_t readCount_;
size_t count_; //!< Number of characters read size_t count_; //!< Number of characters read
bool eof_; bool eof_;
}; };

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FILEWRITESTREAM_H_ #ifndef RAPIDJSON_FILEWRITESTREAM_H_
@ -20,7 +20,7 @@
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(unreachable - code)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -31,13 +31,13 @@ RAPIDJSON_NAMESPACE_BEGIN
*/ */
class FileWriteStream { class FileWriteStream {
public: public:
typedef char Ch; //!< Character type. Only support char. typedef char Ch; //!< Character type. Only support char.
FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
RAPIDJSON_ASSERT(fp_ != 0); RAPIDJSON_ASSERT(fp_ != 0);
} }
void Put(char c) { void Put(char c) {
if (current_ >= bufferEnd_) if (current_ >= bufferEnd_)
Flush(); Flush();
@ -72,11 +72,26 @@ public:
} }
// Not implemented // Not implemented
char Peek() const { RAPIDJSON_ASSERT(false); return 0; } char Peek() const {
char Take() { RAPIDJSON_ASSERT(false); return 0; } RAPIDJSON_ASSERT(false);
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } return 0;
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } }
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } char Take() {
RAPIDJSON_ASSERT(false);
return 0;
}
size_t Tell() const {
RAPIDJSON_ASSERT(false);
return 0;
}
char* PutBegin() {
RAPIDJSON_ASSERT(false);
return 0;
}
size_t PutEnd(char*) {
RAPIDJSON_ASSERT(false);
return 0;
}
private: private:
// Prohibit copy constructor & assignment operator. // Prohibit copy constructor & assignment operator.
@ -84,13 +99,13 @@ private:
FileWriteStream& operator=(const FileWriteStream&); FileWriteStream& operator=(const FileWriteStream&);
std::FILE* fp_; std::FILE* fp_;
char *buffer_; char* buffer_;
char *bufferEnd_; char* bufferEnd_;
char *current_; char* current_;
}; };
//! Implement specialized version of PutN() with memset() for better performance. //! Implement specialized version of PutN() with memset() for better performance.
template<> template <>
inline void PutN(FileWriteStream& stream, char c, size_t n) { inline void PutN(FileWriteStream& stream, char c, size_t n) {
stream.PutN(c, n); stream.PutN(c, n);
} }

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FWD_H_ #ifndef RAPIDJSON_FWD_H_
@ -21,17 +21,26 @@ RAPIDJSON_NAMESPACE_BEGIN
// encodings.h // encodings.h
template<typename CharType> struct UTF8; template <typename CharType>
template<typename CharType> struct UTF16; struct UTF8;
template<typename CharType> struct UTF16BE; template <typename CharType>
template<typename CharType> struct UTF16LE; struct UTF16;
template<typename CharType> struct UTF32; template <typename CharType>
template<typename CharType> struct UTF32BE; struct UTF16BE;
template<typename CharType> struct UTF32LE; template <typename CharType>
template<typename CharType> struct ASCII; struct UTF16LE;
template<typename CharType> struct AutoUTF; template <typename CharType>
struct UTF32;
template <typename CharType>
struct UTF32BE;
template <typename CharType>
struct UTF32LE;
template <typename CharType>
struct ASCII;
template <typename CharType>
struct AutoUTF;
template<typename SourceEncoding, typename TargetEncoding> template <typename SourceEncoding, typename TargetEncoding>
struct Transcoder; struct Transcoder;
// allocators.h // allocators.h
@ -46,12 +55,12 @@ class MemoryPoolAllocator;
template <typename Encoding> template <typename Encoding>
struct GenericStringStream; struct GenericStringStream;
typedef GenericStringStream<UTF8<char> > StringStream; typedef GenericStringStream<UTF8<char>> StringStream;
template <typename Encoding> template <typename Encoding>
struct GenericInsituStringStream; struct GenericInsituStringStream;
typedef GenericInsituStringStream<UTF8<char> > InsituStringStream; typedef GenericInsituStringStream<UTF8<char>> InsituStringStream;
// stringbuffer.h // stringbuffer.h
@ -81,7 +90,7 @@ struct MemoryStream;
// reader.h // reader.h
template<typename Encoding, typename Derived> template <typename Encoding, typename Derived>
struct BaseReaderHandler; struct BaseReaderHandler;
template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator> template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>
@ -91,29 +100,29 @@ typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
// writer.h // writer.h
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags> template <typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
class Writer; class Writer;
// prettywriter.h // prettywriter.h
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags> template <typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
class PrettyWriter; class PrettyWriter;
// document.h // document.h
template <typename Encoding, typename Allocator> template <typename Encoding, typename Allocator>
class GenericMember; class GenericMember;
template <bool Const, typename Encoding, typename Allocator> template <bool Const, typename Encoding, typename Allocator>
class GenericMemberIterator; class GenericMemberIterator;
template<typename CharType> template <typename CharType>
struct GenericStringRef; struct GenericStringRef;
template <typename Encoding, typename Allocator> template <typename Encoding, typename Allocator>
class GenericValue; class GenericValue;
typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value; typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator>> Value;
template <typename Encoding, typename Allocator, typename StackAllocator> template <typename Encoding, typename Allocator, typename StackAllocator>
class GenericDocument; class GenericDocument;

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_BIGINTEGER_H_ #ifndef RAPIDJSON_BIGINTEGER_H_
@ -25,264 +25,274 @@
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
class BigInteger { class BigInteger {
public: public:
typedef uint64_t Type; typedef uint64_t Type;
BigInteger(const BigInteger& rhs) : count_(rhs.count_) { BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
}
explicit BigInteger(uint64_t u) : count_(1) {
digits_[0] = u;
}
BigInteger(const char* decimals, size_t length) : count_(1) {
RAPIDJSON_ASSERT(length > 0);
digits_[0] = 0;
size_t i = 0;
const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
while (length >= kMaxDigitPerIteration) {
AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
length -= kMaxDigitPerIteration;
i += kMaxDigitPerIteration;
}
if (length > 0)
AppendDecimal64(decimals + i, decimals + i + length);
}
BigInteger& operator=(const BigInteger &rhs)
{
if (this != &rhs) {
count_ = rhs.count_;
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
} }
return *this;
}
BigInteger& operator=(uint64_t u) {
digits_[0] = u;
count_ = 1;
return *this;
}
BigInteger& operator+=(uint64_t u) { explicit BigInteger(uint64_t u) : count_(1) {
Type backup = digits_[0]; digits_[0] = u;
digits_[0] += u;
for (size_t i = 0; i < count_ - 1; i++) {
if (digits_[i] >= backup)
return *this; // no carry
backup = digits_[i + 1];
digits_[i + 1] += 1;
} }
// Last carry BigInteger(const char* decimals, size_t length) : count_(1) {
if (digits_[count_ - 1] < backup) RAPIDJSON_ASSERT(length > 0);
PushBack(1); digits_[0] = 0;
size_t i = 0;
const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
while (length >= kMaxDigitPerIteration) {
AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
length -= kMaxDigitPerIteration;
i += kMaxDigitPerIteration;
}
return *this; if (length > 0)
} AppendDecimal64(decimals + i, decimals + i + length);
BigInteger& operator*=(uint64_t u) {
if (u == 0) return *this = 0;
if (u == 1) return *this;
if (*this == 1) return *this = u;
uint64_t k = 0;
for (size_t i = 0; i < count_; i++) {
uint64_t hi;
digits_[i] = MulAdd64(digits_[i], u, k, &hi);
k = hi;
}
if (k > 0)
PushBack(k);
return *this;
}
BigInteger& operator*=(uint32_t u) {
if (u == 0) return *this = 0;
if (u == 1) return *this;
if (*this == 1) return *this = u;
uint64_t k = 0;
for (size_t i = 0; i < count_; i++) {
const uint64_t c = digits_[i] >> 32;
const uint64_t d = digits_[i] & 0xFFFFFFFF;
const uint64_t uc = u * c;
const uint64_t ud = u * d;
const uint64_t p0 = ud + k;
const uint64_t p1 = uc + (p0 >> 32);
digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
k = p1 >> 32;
}
if (k > 0)
PushBack(k);
return *this;
}
BigInteger& operator<<=(size_t shift) {
if (IsZero() || shift == 0) return *this;
size_t offset = shift / kTypeBit;
size_t interShift = shift % kTypeBit;
RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
if (interShift == 0) {
std::memmove(digits_ + offset, digits_, count_ * sizeof(Type));
count_ += offset;
}
else {
digits_[count_] = 0;
for (size_t i = count_; i > 0; i--)
digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
digits_[offset] = digits_[0] << interShift;
count_ += offset;
if (digits_[count_])
count_++;
} }
std::memset(digits_, 0, offset * sizeof(Type)); BigInteger& operator=(const BigInteger& rhs) {
if (this != &rhs) {
return *this; count_ = rhs.count_;
} std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
}
bool operator==(const BigInteger& rhs) const { return *this;
return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
}
bool operator==(const Type rhs) const {
return count_ == 1 && digits_[0] == rhs;
}
BigInteger& MultiplyPow5(unsigned exp) {
static const uint32_t kPow5[12] = {
5,
5 * 5,
5 * 5 * 5,
5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
};
if (exp == 0) return *this;
for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
if (exp > 0) *this *= kPow5[exp - 1];
return *this;
}
// Compute absolute difference of this and rhs.
// Assume this != rhs
bool Difference(const BigInteger& rhs, BigInteger* out) const {
int cmp = Compare(rhs);
RAPIDJSON_ASSERT(cmp != 0);
const BigInteger *a, *b; // Makes a > b
bool ret;
if (cmp < 0) { a = &rhs; b = this; ret = true; }
else { a = this; b = &rhs; ret = false; }
Type borrow = 0;
for (size_t i = 0; i < a->count_; i++) {
Type d = a->digits_[i] - borrow;
if (i < b->count_)
d -= b->digits_[i];
borrow = (d > a->digits_[i]) ? 1 : 0;
out->digits_[i] = d;
if (d != 0)
out->count_ = i + 1;
} }
return ret; BigInteger& operator=(uint64_t u) {
} digits_[0] = u;
count_ = 1;
int Compare(const BigInteger& rhs) const { return *this;
if (count_ != rhs.count_)
return count_ < rhs.count_ ? -1 : 1;
for (size_t i = count_; i-- > 0;)
if (digits_[i] != rhs.digits_[i])
return digits_[i] < rhs.digits_[i] ? -1 : 1;
return 0;
}
size_t GetCount() const { return count_; }
Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
private:
void AppendDecimal64(const char* begin, const char* end) {
uint64_t u = ParseUint64(begin, end);
if (IsZero())
*this = u;
else {
unsigned exp = static_cast<unsigned>(end - begin);
(MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
} }
}
void PushBack(Type digit) { BigInteger& operator+=(uint64_t u) {
RAPIDJSON_ASSERT(count_ < kCapacity); Type backup = digits_[0];
digits_[count_++] = digit; digits_[0] += u;
} for (size_t i = 0; i < count_ - 1; i++) {
if (digits_[i] >= backup)
return *this; // no carry
backup = digits_[i + 1];
digits_[i + 1] += 1;
}
static uint64_t ParseUint64(const char* begin, const char* end) { // Last carry
uint64_t r = 0; if (digits_[count_ - 1] < backup)
for (const char* p = begin; p != end; ++p) { PushBack(1);
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
r = r * 10u + static_cast<unsigned>(*p - '0'); return *this;
} }
return r;
}
// Assume a * b + k < 2^128 BigInteger& operator*=(uint64_t u) {
static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) { if (u == 0) return *this = 0;
if (u == 1) return *this;
if (*this == 1) return *this = u;
uint64_t k = 0;
for (size_t i = 0; i < count_; i++) {
uint64_t hi;
digits_[i] = MulAdd64(digits_[i], u, k, &hi);
k = hi;
}
if (k > 0)
PushBack(k);
return *this;
}
BigInteger& operator*=(uint32_t u) {
if (u == 0) return *this = 0;
if (u == 1) return *this;
if (*this == 1) return *this = u;
uint64_t k = 0;
for (size_t i = 0; i < count_; i++) {
const uint64_t c = digits_[i] >> 32;
const uint64_t d = digits_[i] & 0xFFFFFFFF;
const uint64_t uc = u * c;
const uint64_t ud = u * d;
const uint64_t p0 = ud + k;
const uint64_t p1 = uc + (p0 >> 32);
digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
k = p1 >> 32;
}
if (k > 0)
PushBack(k);
return *this;
}
BigInteger& operator<<=(size_t shift) {
if (IsZero() || shift == 0) return *this;
size_t offset = shift / kTypeBit;
size_t interShift = shift % kTypeBit;
RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
if (interShift == 0) {
std::memmove(digits_ + offset, digits_, count_ * sizeof(Type));
count_ += offset;
}
else {
digits_[count_] = 0;
for (size_t i = count_; i > 0; i--)
digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
digits_[offset] = digits_[0] << interShift;
count_ += offset;
if (digits_[count_])
count_++;
}
std::memset(digits_, 0, offset * sizeof(Type));
return *this;
}
bool operator==(const BigInteger& rhs) const {
return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
}
bool operator==(const Type rhs) const {
return count_ == 1 && digits_[0] == rhs;
}
BigInteger& MultiplyPow5(unsigned exp) {
static const uint32_t kPow5[12] = {
5,
5 * 5,
5 * 5 * 5,
5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
};
if (exp == 0) return *this;
for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
if (exp > 0) *this *= kPow5[exp - 1];
return *this;
}
// Compute absolute difference of this and rhs.
// Assume this != rhs
bool Difference(const BigInteger& rhs, BigInteger* out) const {
int cmp = Compare(rhs);
RAPIDJSON_ASSERT(cmp != 0);
const BigInteger *a, *b; // Makes a > b
bool ret;
if (cmp < 0) {
a = &rhs;
b = this;
ret = true;
}
else {
a = this;
b = &rhs;
ret = false;
}
Type borrow = 0;
for (size_t i = 0; i < a->count_; i++) {
Type d = a->digits_[i] - borrow;
if (i < b->count_)
d -= b->digits_[i];
borrow = (d > a->digits_[i]) ? 1 : 0;
out->digits_[i] = d;
if (d != 0)
out->count_ = i + 1;
}
return ret;
}
int Compare(const BigInteger& rhs) const {
if (count_ != rhs.count_)
return count_ < rhs.count_ ? -1 : 1;
for (size_t i = count_; i-- > 0;)
if (digits_[i] != rhs.digits_[i])
return digits_[i] < rhs.digits_[i] ? -1 : 1;
return 0;
}
size_t GetCount() const { return count_; }
Type GetDigit(size_t index) const {
RAPIDJSON_ASSERT(index < count_);
return digits_[index];
}
bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
private:
void AppendDecimal64(const char* begin, const char* end) {
uint64_t u = ParseUint64(begin, end);
if (IsZero())
*this = u;
else {
unsigned exp = static_cast<unsigned>(end - begin);
(MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
}
}
void PushBack(Type digit) {
RAPIDJSON_ASSERT(count_ < kCapacity);
digits_[count_++] = digit;
}
static uint64_t ParseUint64(const char* begin, const char* end) {
uint64_t r = 0;
for (const char* p = begin; p != end; ++p) {
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
r = r * 10u + static_cast<unsigned>(*p - '0');
}
return r;
}
// Assume a * b + k < 2^128
static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
#if defined(_MSC_VER) && defined(_M_AMD64) #if defined(_MSC_VER) && defined(_M_AMD64)
uint64_t low = _umul128(a, b, outHigh) + k; uint64_t low = _umul128(a, b, outHigh) + k;
if (low < k) if (low < k)
(*outHigh)++; (*outHigh)++;
return low; return low;
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
__extension__ typedef unsigned __int128 uint128; __extension__ typedef unsigned __int128 uint128;
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b); uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
p += k; p += k;
*outHigh = static_cast<uint64_t>(p >> 64); *outHigh = static_cast<uint64_t>(p >> 64);
return static_cast<uint64_t>(p); return static_cast<uint64_t>(p);
#else #else
const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32; const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1; uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
x1 += (x0 >> 32); // can't give carry x1 += (x0 >> 32); // can't give carry
x1 += x2; x1 += x2;
if (x1 < x2) if (x1 < x2)
x3 += (static_cast<uint64_t>(1) << 32); x3 += (static_cast<uint64_t>(1) << 32);
uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF); uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
uint64_t hi = x3 + (x1 >> 32); uint64_t hi = x3 + (x1 >> 32);
lo += k; lo += k;
if (lo < k) if (lo < k)
hi++; hi++;
*outHigh = hi; *outHigh = hi;
return lo; return lo;
#endif #endif
} }
static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
static const size_t kCapacity = kBitCount / sizeof(Type); static const size_t kCapacity = kBitCount / sizeof(Type);
static const size_t kTypeBit = sizeof(Type) * 8; static const size_t kTypeBit = sizeof(Type) * 8;
Type digits_[kCapacity]; Type digits_[kCapacity];
size_t count_; size_t count_;
}; };
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View File

@ -29,39 +29,39 @@
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
inline uint32_t clzll(uint64_t x) { inline uint32_t clzll(uint64_t x) {
// Passing 0 to __builtin_clzll is UB in GCC and results in an // Passing 0 to __builtin_clzll is UB in GCC and results in an
// infinite loop in the software implementation. // infinite loop in the software implementation.
RAPIDJSON_ASSERT(x != 0); RAPIDJSON_ASSERT(x != 0);
#if defined(_MSC_VER) && !defined(UNDER_CE) #if defined(_MSC_VER) && !defined(UNDER_CE)
unsigned long r = 0; unsigned long r = 0;
#if defined(_WIN64) #if defined(_WIN64)
_BitScanReverse64(&r, x); _BitScanReverse64(&r, x);
#else #else
// Scan the high 32 bits. // Scan the high 32 bits.
if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32))) if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
return 63 - (r + 32); return 63 - (r + 32);
// Scan the low 32 bits. // Scan the low 32 bits.
_BitScanReverse(&r, static_cast<uint32_t>(x & 0xFFFFFFFF)); _BitScanReverse(&r, static_cast<uint32_t>(x & 0xFFFFFFFF));
#endif // _WIN64 #endif // _WIN64
return 63 - r; return 63 - r;
#elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll) #elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll)
// __builtin_clzll wrapper // __builtin_clzll wrapper
return static_cast<uint32_t>(__builtin_clzll(x)); return static_cast<uint32_t>(__builtin_clzll(x));
#else #else
// naive version // naive version
uint32_t r = 0; uint32_t r = 0;
while (!(x & (static_cast<uint64_t>(1) << 63))) { while (!(x & (static_cast<uint64_t>(1) << 63))) {
x <<= 1; x <<= 1;
++r; ++r;
} }
return r; return r;
#endif // _MSC_VER #endif // _MSC_VER
} }
#define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll #define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll

View File

@ -32,223 +32,222 @@ RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
#endif #endif
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(padded)
#endif #endif
struct DiyFp { struct DiyFp {
DiyFp() : f(), e() {} DiyFp() : f(), e() {}
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
explicit DiyFp(double d) { explicit DiyFp(double d) {
union { union {
double d; double d;
uint64_t u64; uint64_t u64;
} u = { d }; } u = { d };
int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize); int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
uint64_t significand = (u.u64 & kDpSignificandMask); uint64_t significand = (u.u64 & kDpSignificandMask);
if (biased_e != 0) { if (biased_e != 0) {
f = significand + kDpHiddenBit; f = significand + kDpHiddenBit;
e = biased_e - kDpExponentBias; e = biased_e - kDpExponentBias;
}
else {
f = significand;
e = kDpMinExponent + 1;
}
} }
else {
f = significand; DiyFp operator-(const DiyFp& rhs) const {
e = kDpMinExponent + 1; return DiyFp(f - rhs.f, e);
} }
}
DiyFp operator-(const DiyFp& rhs) const { DiyFp operator*(const DiyFp& rhs) const {
return DiyFp(f - rhs.f, e);
}
DiyFp operator*(const DiyFp& rhs) const {
#if defined(_MSC_VER) && defined(_M_AMD64) #if defined(_MSC_VER) && defined(_M_AMD64)
uint64_t h; uint64_t h;
uint64_t l = _umul128(f, rhs.f, &h); uint64_t l = _umul128(f, rhs.f, &h);
if (l & (uint64_t(1) << 63)) // rounding if (l & (uint64_t(1) << 63)) // rounding
h++; h++;
return DiyFp(h, e + rhs.e + 64); return DiyFp(h, e + rhs.e + 64);
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
__extension__ typedef unsigned __int128 uint128; __extension__ typedef unsigned __int128 uint128;
uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f); uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
uint64_t h = static_cast<uint64_t>(p >> 64); uint64_t h = static_cast<uint64_t>(p >> 64);
uint64_t l = static_cast<uint64_t>(p); uint64_t l = static_cast<uint64_t>(p);
if (l & (uint64_t(1) << 63)) // rounding if (l & (uint64_t(1) << 63)) // rounding
h++; h++;
return DiyFp(h, e + rhs.e + 64); return DiyFp(h, e + rhs.e + 64);
#else #else
const uint64_t M32 = 0xFFFFFFFF; const uint64_t M32 = 0xFFFFFFFF;
const uint64_t a = f >> 32; const uint64_t a = f >> 32;
const uint64_t b = f & M32; const uint64_t b = f & M32;
const uint64_t c = rhs.f >> 32; const uint64_t c = rhs.f >> 32;
const uint64_t d = rhs.f & M32; const uint64_t d = rhs.f & M32;
const uint64_t ac = a * c; const uint64_t ac = a * c;
const uint64_t bc = b * c; const uint64_t bc = b * c;
const uint64_t ad = a * d; const uint64_t ad = a * d;
const uint64_t bd = b * d; const uint64_t bd = b * d;
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
tmp += 1U << 31; /// mult_round tmp += 1U << 31; /// mult_round
return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
#endif #endif
}
DiyFp Normalize() const {
int s = static_cast<int>(clzll(f));
return DiyFp(f << s, e - s);
}
DiyFp NormalizeBoundary() const {
DiyFp res = *this;
while (!(res.f & (kDpHiddenBit << 1))) {
res.f <<= 1;
res.e--;
} }
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
return res;
}
void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { DiyFp Normalize() const {
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); int s = static_cast<int>(clzll(f));
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); return DiyFp(f << s, e - s);
mi.f <<= mi.e - pl.e;
mi.e = pl.e;
*plus = pl;
*minus = mi;
}
double ToDouble() const {
union {
double d;
uint64_t u64;
}u;
RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask);
if (e < kDpDenormalExponent) {
// Underflow.
return 0.0;
} }
if (e >= kDpMaxExponent) {
// Overflow. DiyFp NormalizeBoundary() const {
return std::numeric_limits<double>::infinity(); DiyFp res = *this;
while (!(res.f & (kDpHiddenBit << 1))) {
res.f <<= 1;
res.e--;
}
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
return res;
} }
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
static_cast<uint64_t>(e + kDpExponentBias);
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
return u.d;
}
static const int kDiySignificandSize = 64; void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
static const int kDpSignificandSize = 52; DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
static const int kDpExponentBias = 0x3FF + kDpSignificandSize; DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
static const int kDpMaxExponent = 0x7FF - kDpExponentBias; mi.f <<= mi.e - pl.e;
static const int kDpMinExponent = -kDpExponentBias; mi.e = pl.e;
static const int kDpDenormalExponent = -kDpExponentBias + 1; *plus = pl;
static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); *minus = mi;
static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); }
static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
uint64_t f; double ToDouble() const {
int e; union {
}; double d;
uint64_t u64;
} u;
RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask);
if (e < kDpDenormalExponent) {
// Underflow.
return 0.0;
}
if (e >= kDpMaxExponent) {
// Overflow.
return std::numeric_limits<double>::infinity();
}
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : static_cast<uint64_t>(e + kDpExponentBias);
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
return u.d;
}
inline DiyFp GetCachedPowerByIndex(size_t index) { static const int kDiySignificandSize = 64;
// 10^-348, 10^-340, ..., 10^340 static const int kDpSignificandSize = 52;
static const uint64_t kCachedPowers_F[] = { static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), static const int kDpMinExponent = -kDpExponentBias;
RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), static const int kDpDenormalExponent = -kDpExponentBias + 1;
RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), uint64_t f;
RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), int e;
RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
}; };
static const int16_t kCachedPowers_E[] = {
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
907, 933, 960, 986, 1013, 1039, 1066
};
RAPIDJSON_ASSERT(index < 87);
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
}
inline DiyFp GetCachedPower(int e, int* K) { inline DiyFp GetCachedPowerByIndex(size_t index) {
// 10^-348, 10^-340, ..., 10^340
static const uint64_t kCachedPowers_F[] = {
RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
};
static const int16_t kCachedPowers_E[] = {
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
907, 933, 960, 986, 1013, 1039, 1066
};
RAPIDJSON_ASSERT(index < 87);
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
}
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374; inline DiyFp GetCachedPower(int e, int* K) {
double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
int k = static_cast<int>(dk);
if (dk - k > 0.0)
k++;
unsigned index = static_cast<unsigned>((k >> 3) + 1); //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
int k = static_cast<int>(dk);
if (dk - k > 0.0)
k++;
return GetCachedPowerByIndex(index); unsigned index = static_cast<unsigned>((k >> 3) + 1);
} *K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
inline DiyFp GetCachedPower10(int exp, int *outExp) { return GetCachedPowerByIndex(index);
RAPIDJSON_ASSERT(exp >= -348); }
unsigned index = static_cast<unsigned>(exp + 348) / 8u;
*outExp = -348 + static_cast<int>(index) * 8; inline DiyFp GetCachedPower10(int exp, int* outExp) {
return GetCachedPowerByIndex(index); RAPIDJSON_ASSERT(exp >= -348);
} unsigned index = static_cast<unsigned>(exp + 348) / 8u;
*outExp = -348 + static_cast<int>(index) * 8;
return GetCachedPowerByIndex(index);
}
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(padded)
#endif #endif
} // namespace internal } // namespace internal

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
// This is a C++ header-only implementation of Grisu2 algorithm from the publication: // This is a C++ header-only implementation of Grisu2 algorithm from the publication:
@ -27,216 +27,243 @@ RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 RAPIDJSON_DIAG_OFF(array - bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
#endif #endif
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
while (rest < wp_w && delta - rest >= ten_kappa && while (rest < wp_w && delta - rest >= ten_kappa &&
(rest + ten_kappa < wp_w || /// closer (rest + ten_kappa < wp_w || /// closer
wp_w - rest > rest + ten_kappa - wp_w)) { wp_w - rest > rest + ten_kappa - wp_w)) {
buffer[len - 1]--; buffer[len - 1]--;
rest += ten_kappa; rest += ten_kappa;
}
} }
}
inline int CountDecimalDigit32(uint32_t n) { inline int CountDecimalDigit32(uint32_t n) {
// Simple pure C++ implementation was faster than __builtin_clz version in this situation. // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
if (n < 10) return 1; if (n < 10) return 1;
if (n < 100) return 2; if (n < 100) return 2;
if (n < 1000) return 3; if (n < 1000) return 3;
if (n < 10000) return 4; if (n < 10000) return 4;
if (n < 100000) return 5; if (n < 100000) return 5;
if (n < 1000000) return 6; if (n < 1000000) return 6;
if (n < 10000000) return 7; if (n < 10000000) return 7;
if (n < 100000000) return 8; if (n < 100000000) return 8;
// Will not reach 10 digits in DigitGen() // Will not reach 10 digits in DigitGen()
//if (n < 1000000000) return 9; //if (n < 1000000000) return 9;
//return 10; //return 10;
return 9; return 9;
} }
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
const DiyFp wp_w = Mp - W; const DiyFp wp_w = Mp - W;
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e); uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
uint64_t p2 = Mp.f & (one.f - 1); uint64_t p2 = Mp.f & (one.f - 1);
int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
*len = 0; *len = 0;
while (kappa > 0) { while (kappa > 0) {
uint32_t d = 0; uint32_t d = 0;
switch (kappa) { switch (kappa) {
case 9: d = p1 / 100000000; p1 %= 100000000; break; case 9:
case 8: d = p1 / 10000000; p1 %= 10000000; break; d = p1 / 100000000;
case 7: d = p1 / 1000000; p1 %= 1000000; break; p1 %= 100000000;
case 6: d = p1 / 100000; p1 %= 100000; break; break;
case 5: d = p1 / 10000; p1 %= 10000; break; case 8:
case 4: d = p1 / 1000; p1 %= 1000; break; d = p1 / 10000000;
case 3: d = p1 / 100; p1 %= 100; break; p1 %= 10000000;
case 2: d = p1 / 10; p1 %= 10; break; break;
case 1: d = p1; p1 = 0; break; case 7:
d = p1 / 1000000;
p1 %= 1000000;
break;
case 6:
d = p1 / 100000;
p1 %= 100000;
break;
case 5:
d = p1 / 10000;
p1 %= 10000;
break;
case 4:
d = p1 / 1000;
p1 %= 1000;
break;
case 3:
d = p1 / 100;
p1 %= 100;
break;
case 2:
d = p1 / 10;
p1 %= 10;
break;
case 1:
d = p1;
p1 = 0;
break;
default:; default:;
}
if (d || *len)
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
kappa--;
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
if (tmp <= delta) {
*K += kappa;
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
return;
}
} }
if (d || *len)
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d)); // kappa = 0
kappa--; for (;;) {
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2; p2 *= 10;
if (tmp <= delta) { delta *= 10;
*K += kappa; char d = static_cast<char>(p2 >> -one.e);
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f); if (d || *len)
return; buffer[(*len)++] = static_cast<char>('0' + d);
p2 &= one.f - 1;
kappa--;
if (p2 < delta) {
*K += kappa;
int index = -kappa;
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0));
return;
}
} }
} }
// kappa = 0 inline void Grisu2(double value, char* buffer, int* length, int* K) {
for (;;) { const DiyFp v(value);
p2 *= 10; DiyFp w_m, w_p;
delta *= 10; v.NormalizedBoundaries(&w_m, &w_p);
char d = static_cast<char>(p2 >> -one.e);
if (d || *len)
buffer[(*len)++] = static_cast<char>('0' + d);
p2 &= one.f - 1;
kappa--;
if (p2 < delta) {
*K += kappa;
int index = -kappa;
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0));
return;
}
}
}
inline void Grisu2(double value, char* buffer, int* length, int* K) { const DiyFp c_mk = GetCachedPower(w_p.e, K);
const DiyFp v(value); const DiyFp W = v.Normalize() * c_mk;
DiyFp w_m, w_p; DiyFp Wp = w_p * c_mk;
v.NormalizedBoundaries(&w_m, &w_p); DiyFp Wm = w_m * c_mk;
Wm.f++;
const DiyFp c_mk = GetCachedPower(w_p.e, K); Wp.f--;
const DiyFp W = v.Normalize() * c_mk; DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
DiyFp Wp = w_p * c_mk;
DiyFp Wm = w_m * c_mk;
Wm.f++;
Wp.f--;
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
}
inline char* WriteExponent(int K, char* buffer) {
if (K < 0) {
*buffer++ = '-';
K = -K;
} }
if (K >= 100) { inline char* WriteExponent(int K, char* buffer) {
*buffer++ = static_cast<char>('0' + static_cast<char>(K / 100)); if (K < 0) {
K %= 100;
const char* d = GetDigitsLut() + K * 2;
*buffer++ = d[0];
*buffer++ = d[1];
}
else if (K >= 10) {
const char* d = GetDigitsLut() + K * 2;
*buffer++ = d[0];
*buffer++ = d[1];
}
else
*buffer++ = static_cast<char>('0' + static_cast<char>(K));
return buffer;
}
inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
if (0 <= k && kk <= 21) {
// 1234e7 -> 12340000000
for (int i = length; i < kk; i++)
buffer[i] = '0';
buffer[kk] = '.';
buffer[kk + 1] = '0';
return &buffer[kk + 2];
}
else if (0 < kk && kk <= 21) {
// 1234e-2 -> 12.34
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
buffer[kk] = '.';
if (0 > k + maxDecimalPlaces) {
// When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
// Remove extra trailing zeros (at least one) after truncation.
for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
if (buffer[i] != '0')
return &buffer[i + 1];
return &buffer[kk + 2]; // Reserve one zero
}
else
return &buffer[length + 1];
}
else if (-6 < kk && kk <= 0) {
// 1234e-6 -> 0.001234
const int offset = 2 - kk;
std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
buffer[0] = '0';
buffer[1] = '.';
for (int i = 2; i < offset; i++)
buffer[i] = '0';
if (length - kk > maxDecimalPlaces) {
// When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
// Remove extra trailing zeros (at least one) after truncation.
for (int i = maxDecimalPlaces + 1; i > 2; i--)
if (buffer[i] != '0')
return &buffer[i + 1];
return &buffer[3]; // Reserve one zero
}
else
return &buffer[length + offset];
}
else if (kk < -maxDecimalPlaces) {
// Truncate to zero
buffer[0] = '0';
buffer[1] = '.';
buffer[2] = '0';
return &buffer[3];
}
else if (length == 1) {
// 1e30
buffer[1] = 'e';
return WriteExponent(kk - 1, &buffer[2]);
}
else {
// 1234e30 -> 1.234e33
std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
buffer[1] = '.';
buffer[length + 1] = 'e';
return WriteExponent(kk - 1, &buffer[0 + length + 2]);
}
}
inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
Double d(value);
if (d.IsZero()) {
if (d.Sign())
*buffer++ = '-'; // -0.0, Issue #289
buffer[0] = '0';
buffer[1] = '.';
buffer[2] = '0';
return &buffer[3];
}
else {
if (value < 0) {
*buffer++ = '-'; *buffer++ = '-';
value = -value; K = -K;
}
if (K >= 100) {
*buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
K %= 100;
const char* d = GetDigitsLut() + K * 2;
*buffer++ = d[0];
*buffer++ = d[1];
}
else if (K >= 10) {
const char* d = GetDigitsLut() + K * 2;
*buffer++ = d[0];
*buffer++ = d[1];
}
else
*buffer++ = static_cast<char>('0' + static_cast<char>(K));
return buffer;
}
inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
if (0 <= k && kk <= 21) {
// 1234e7 -> 12340000000
for (int i = length; i < kk; i++)
buffer[i] = '0';
buffer[kk] = '.';
buffer[kk + 1] = '0';
return &buffer[kk + 2];
}
else if (0 < kk && kk <= 21) {
// 1234e-2 -> 12.34
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
buffer[kk] = '.';
if (0 > k + maxDecimalPlaces) {
// When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
// Remove extra trailing zeros (at least one) after truncation.
for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
if (buffer[i] != '0')
return &buffer[i + 1];
return &buffer[kk + 2]; // Reserve one zero
}
else
return &buffer[length + 1];
}
else if (-6 < kk && kk <= 0) {
// 1234e-6 -> 0.001234
const int offset = 2 - kk;
std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
buffer[0] = '0';
buffer[1] = '.';
for (int i = 2; i < offset; i++)
buffer[i] = '0';
if (length - kk > maxDecimalPlaces) {
// When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
// Remove extra trailing zeros (at least one) after truncation.
for (int i = maxDecimalPlaces + 1; i > 2; i--)
if (buffer[i] != '0')
return &buffer[i + 1];
return &buffer[3]; // Reserve one zero
}
else
return &buffer[length + offset];
}
else if (kk < -maxDecimalPlaces) {
// Truncate to zero
buffer[0] = '0';
buffer[1] = '.';
buffer[2] = '0';
return &buffer[3];
}
else if (length == 1) {
// 1e30
buffer[1] = 'e';
return WriteExponent(kk - 1, &buffer[2]);
}
else {
// 1234e30 -> 1.234e33
std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
buffer[1] = '.';
buffer[length + 1] = 'e';
return WriteExponent(kk - 1, &buffer[0 + length + 2]);
}
}
inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
Double d(value);
if (d.IsZero()) {
if (d.Sign())
*buffer++ = '-'; // -0.0, Issue #289
buffer[0] = '0';
buffer[1] = '.';
buffer[2] = '0';
return &buffer[3];
}
else {
if (value < 0) {
*buffer++ = '-';
value = -value;
}
int length, K;
Grisu2(value, buffer, &length, &K);
return Prettify(buffer, length, K, maxDecimalPlaces);
} }
int length, K;
Grisu2(value, buffer, &length, &K);
return Prettify(buffer, length, K, maxDecimalPlaces);
} }
}
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
} // namespace internal } // namespace internal

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_IEEE754_ #ifndef RAPIDJSON_IEEE754_
@ -20,57 +20,57 @@
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
class Double { class Double {
public: public:
Double() {} Double() {}
Double(double d) : d_(d) {} Double(double d) : d_(d) {}
Double(uint64_t u) : u_(u) {} Double(uint64_t u) : u_(u) {}
double Value() const { return d_; } double Value() const { return d_; }
uint64_t Uint64Value() const { return u_; } uint64_t Uint64Value() const { return u_; }
double NextPositiveDouble() const { double NextPositiveDouble() const {
RAPIDJSON_ASSERT(!Sign()); RAPIDJSON_ASSERT(!Sign());
return Double(u_ + 1).Value(); return Double(u_ + 1).Value();
} }
bool Sign() const { return (u_ & kSignMask) != 0; } bool Sign() const { return (u_ & kSignMask) != 0; }
uint64_t Significand() const { return u_ & kSignificandMask; } uint64_t Significand() const { return u_ & kSignificandMask; }
int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
static int EffectiveSignificandSize(int order) { static int EffectiveSignificandSize(int order) {
if (order >= -1021) if (order >= -1021)
return 53; return 53;
else if (order <= -1074) else if (order <= -1074)
return 0; return 0;
else else
return order + 1074; return order + 1074;
} }
private: private:
static const int kSignificandSize = 52; static const int kSignificandSize = 52;
static const int kExponentBias = 0x3FF; static const int kExponentBias = 0x3FF;
static const int kDenormalExponent = 1 - kExponentBias; static const int kDenormalExponent = 1 - kExponentBias;
static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
union { union {
double d_; double d_;
uint64_t u_; uint64_t u_;
};
}; };
};
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View File

@ -20,140 +20,43 @@
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
inline const char* GetDigitsLut() { inline const char* GetDigitsLut() {
static const char cDigitsLut[200] = { static const char cDigitsLut[200] = {
'0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', '7', '0', '8', '0', '9',
'1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', '1', '5', '1', '6', '1', '7', '1', '8', '1', '9',
'2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9', '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
'3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9', '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', '7', '3', '8', '3', '9',
'4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9', '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', '4', '5', '4', '6', '4', '7', '4', '8', '4', '9',
'5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9', '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
'6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9', '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', '7', '6', '8', '6', '9',
'7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', '7', '5', '7', '6', '7', '7', '7', '8', '7', '9',
'8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9', '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
'9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', '7', '9', '8', '9', '9'
}; };
return cDigitsLut; return cDigitsLut;
}
inline char* u32toa(uint32_t value, char* buffer) {
RAPIDJSON_ASSERT(buffer != 0);
const char* cDigitsLut = GetDigitsLut();
if (value < 10000) {
const uint32_t d1 = (value / 100) << 1;
const uint32_t d2 = (value % 100) << 1;
if (value >= 1000)
*buffer++ = cDigitsLut[d1];
if (value >= 100)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 10)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
}
else if (value < 100000000) {
// value = bbbbcccc
const uint32_t b = value / 10000;
const uint32_t c = value % 10000;
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
if (value >= 10000000)
*buffer++ = cDigitsLut[d1];
if (value >= 1000000)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 100000)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
else {
// value = aabbbbcccc in decimal
const uint32_t a = value / 100000000; // 1 to 42
value %= 100000000;
if (a >= 10) {
const unsigned i = a << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
const uint32_t b = value / 10000; // 0 to 9999
const uint32_t c = value % 10000; // 0 to 9999
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
return buffer;
}
inline char* i32toa(int32_t value, char* buffer) {
RAPIDJSON_ASSERT(buffer != 0);
uint32_t u = static_cast<uint32_t>(value);
if (value < 0) {
*buffer++ = '-';
u = ~u + 1;
} }
return u32toa(u, buffer); inline char* u32toa(uint32_t value, char* buffer) {
} RAPIDJSON_ASSERT(buffer != 0);
inline char* u64toa(uint64_t value, char* buffer) { const char* cDigitsLut = GetDigitsLut();
RAPIDJSON_ASSERT(buffer != 0);
const char* cDigitsLut = GetDigitsLut();
const uint64_t kTen8 = 100000000;
const uint64_t kTen9 = kTen8 * 10;
const uint64_t kTen10 = kTen8 * 100;
const uint64_t kTen11 = kTen8 * 1000;
const uint64_t kTen12 = kTen8 * 10000;
const uint64_t kTen13 = kTen8 * 100000;
const uint64_t kTen14 = kTen8 * 1000000;
const uint64_t kTen15 = kTen8 * 10000000;
const uint64_t kTen16 = kTen8 * kTen8;
if (value < kTen8) { if (value < 10000) {
uint32_t v = static_cast<uint32_t>(value); const uint32_t d1 = (value / 100) << 1;
if (v < 10000) { const uint32_t d2 = (value % 100) << 1;
const uint32_t d1 = (v / 100) << 1;
const uint32_t d2 = (v % 100) << 1;
if (v >= 1000) if (value >= 1000)
*buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1];
if (v >= 100) if (value >= 100)
*buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d1 + 1];
if (v >= 10) if (value >= 10)
*buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d2 + 1];
} }
else { else if (value < 100000000) {
// value = bbbbcccc // value = bbbbcccc
const uint32_t b = v / 10000; const uint32_t b = value / 10000;
const uint32_t c = v % 10000; const uint32_t c = value % 10000;
const uint32_t d1 = (b / 100) << 1; const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1; const uint32_t d2 = (b % 100) << 1;
@ -174,134 +77,231 @@ inline char* u64toa(uint64_t value, char* buffer) {
*buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d4 + 1];
} }
} else {
else if (value < kTen16) { // value = aabbbbcccc in decimal
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
const uint32_t b0 = v0 / 10000; const uint32_t a = value / 100000000; // 1 to 42
const uint32_t c0 = v0 % 10000; value %= 100000000;
const uint32_t d1 = (b0 / 100) << 1; if (a >= 10) {
const uint32_t d2 = (b0 % 100) << 1; const unsigned i = a << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
const uint32_t d3 = (c0 / 100) << 1; const uint32_t b = value / 10000; // 0 to 9999
const uint32_t d4 = (c0 % 100) << 1; const uint32_t c = value % 10000; // 0 to 9999
const uint32_t b1 = v1 / 10000; const uint32_t d1 = (b / 100) << 1;
const uint32_t c1 = v1 % 10000; const uint32_t d2 = (b % 100) << 1;
const uint32_t d5 = (b1 / 100) << 1; const uint32_t d3 = (c / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1; const uint32_t d4 = (c % 100) << 1;
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
if (value >= kTen15)
*buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1];
if (value >= kTen14)
*buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d1 + 1];
if (value >= kTen13)
*buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2];
if (value >= kTen12)
*buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d2 + 1];
if (value >= kTen11)
*buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3];
if (value >= kTen10)
*buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d3 + 1];
if (value >= kTen9)
*buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
*buffer++ = cDigitsLut[d4 + 1];
*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
*buffer++ = cDigitsLut[d6 + 1];
*buffer++ = cDigitsLut[d7];
*buffer++ = cDigitsLut[d7 + 1];
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
}
else {
const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
value %= kTen16;
if (a < 10)
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
else if (a < 100) {
const uint32_t i = a << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
} }
else if (a < 1000) { return buffer;
*buffer++ = static_cast<char>('0' + static_cast<char>(a / 100)); }
const uint32_t i = (a % 100) << 1; inline char* i32toa(int32_t value, char* buffer) {
*buffer++ = cDigitsLut[i]; RAPIDJSON_ASSERT(buffer != 0);
*buffer++ = cDigitsLut[i + 1]; uint32_t u = static_cast<uint32_t>(value);
if (value < 0) {
*buffer++ = '-';
u = ~u + 1;
}
return u32toa(u, buffer);
}
inline char* u64toa(uint64_t value, char* buffer) {
RAPIDJSON_ASSERT(buffer != 0);
const char* cDigitsLut = GetDigitsLut();
const uint64_t kTen8 = 100000000;
const uint64_t kTen9 = kTen8 * 10;
const uint64_t kTen10 = kTen8 * 100;
const uint64_t kTen11 = kTen8 * 1000;
const uint64_t kTen12 = kTen8 * 10000;
const uint64_t kTen13 = kTen8 * 100000;
const uint64_t kTen14 = kTen8 * 1000000;
const uint64_t kTen15 = kTen8 * 10000000;
const uint64_t kTen16 = kTen8 * kTen8;
if (value < kTen8) {
uint32_t v = static_cast<uint32_t>(value);
if (v < 10000) {
const uint32_t d1 = (v / 100) << 1;
const uint32_t d2 = (v % 100) << 1;
if (v >= 1000)
*buffer++ = cDigitsLut[d1];
if (v >= 100)
*buffer++ = cDigitsLut[d1 + 1];
if (v >= 10)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
}
else {
// value = bbbbcccc
const uint32_t b = v / 10000;
const uint32_t c = v % 10000;
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
if (value >= 10000000)
*buffer++ = cDigitsLut[d1];
if (value >= 1000000)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 100000)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
}
else if (value < kTen16) {
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
if (value >= kTen15)
*buffer++ = cDigitsLut[d1];
if (value >= kTen14)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= kTen13)
*buffer++ = cDigitsLut[d2];
if (value >= kTen12)
*buffer++ = cDigitsLut[d2 + 1];
if (value >= kTen11)
*buffer++ = cDigitsLut[d3];
if (value >= kTen10)
*buffer++ = cDigitsLut[d3 + 1];
if (value >= kTen9)
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
*buffer++ = cDigitsLut[d6 + 1];
*buffer++ = cDigitsLut[d7];
*buffer++ = cDigitsLut[d7 + 1];
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
} }
else { else {
const uint32_t i = (a / 100) << 1; const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
const uint32_t j = (a % 100) << 1; value %= kTen16;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1]; if (a < 10)
*buffer++ = cDigitsLut[j]; *buffer++ = static_cast<char>('0' + static_cast<char>(a));
*buffer++ = cDigitsLut[j + 1]; else if (a < 100) {
const uint32_t i = a << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else if (a < 1000) {
*buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
const uint32_t i = (a % 100) << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else {
const uint32_t i = (a / 100) << 1;
const uint32_t j = (a % 100) << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
*buffer++ = cDigitsLut[j];
*buffer++ = cDigitsLut[j + 1];
}
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
*buffer++ = cDigitsLut[d6 + 1];
*buffer++ = cDigitsLut[d7];
*buffer++ = cDigitsLut[d7 + 1];
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
} }
const uint32_t v0 = static_cast<uint32_t>(value / kTen8); return buffer;
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
*buffer++ = cDigitsLut[d6 + 1];
*buffer++ = cDigitsLut[d7];
*buffer++ = cDigitsLut[d7 + 1];
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
} }
return buffer; inline char* i64toa(int64_t value, char* buffer) {
} RAPIDJSON_ASSERT(buffer != 0);
uint64_t u = static_cast<uint64_t>(value);
if (value < 0) {
*buffer++ = '-';
u = ~u + 1;
}
inline char* i64toa(int64_t value, char* buffer) { return u64toa(u, buffer);
RAPIDJSON_ASSERT(buffer != 0);
uint64_t u = static_cast<uint64_t>(value);
if (value < 0) {
*buffer++ = '-';
u = ~u + 1;
} }
return u64toa(u, buffer);
}
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_META_H_ #ifndef RAPIDJSON_INTERNAL_META_H_
@ -35,141 +35,177 @@ RAPIDJSON_DIAG_OFF(6334)
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
template <typename T> struct Void { typedef void Type; }; template <typename T>
struct Void { typedef void Type; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// BoolType, TrueType, FalseType // BoolType, TrueType, FalseType
// //
template <bool Cond> struct BoolType { template <bool Cond>
static const bool Value = Cond; struct BoolType {
typedef BoolType Type; static const bool Value = Cond;
}; typedef BoolType Type;
typedef BoolType<true> TrueType; };
typedef BoolType<false> FalseType; typedef BoolType<true> TrueType;
typedef BoolType<false> FalseType;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr // SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
// //
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; }; template <bool C>
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; }; struct SelectIfImpl {
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {}; template <typename T1, typename T2>
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {}; struct Apply { typedef T1 Type; };
};
template <>
struct SelectIfImpl<false> {
template <typename T1, typename T2>
struct Apply { typedef T2 Type; };
};
template <bool C, typename T1, typename T2>
struct SelectIfCond : SelectIfImpl<C>::template Apply<T1, T2> {};
template <typename C, typename T1, typename T2>
struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {}; template <bool Cond1, bool Cond2>
template <> struct AndExprCond<true, true> : TrueType {}; struct AndExprCond : FalseType {};
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {}; template <>
template <> struct OrExprCond<false, false> : FalseType {}; struct AndExprCond<true, true> : TrueType {};
template <bool Cond1, bool Cond2>
struct OrExprCond : TrueType {};
template <>
struct OrExprCond<false, false> : FalseType {};
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {}; template <typename C>
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {}; struct BoolExpr : SelectIf<C, TrueType, FalseType>::Type {};
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {}; template <typename C>
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {}; struct NotExpr : SelectIf<C, FalseType, TrueType>::Type {};
template <typename C1, typename C2>
struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
template <typename C1, typename C2>
struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// AddConst, MaybeAddConst, RemoveConst // AddConst, MaybeAddConst, RemoveConst
template <typename T> struct AddConst { typedef const T Type; }; template <typename T>
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {}; struct AddConst { typedef const T Type; };
template <typename T> struct RemoveConst { typedef T Type; }; template <bool Constify, typename T>
template <typename T> struct RemoveConst<const T> { typedef T Type; }; struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
template <typename T>
struct RemoveConst { typedef T Type; };
template <typename T>
struct RemoveConst<const T> { typedef T Type; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// IsSame, IsConst, IsMoreConst, IsPointer // IsSame, IsConst, IsMoreConst, IsPointer
// //
template <typename T, typename U> struct IsSame : FalseType {}; template <typename T, typename U>
template <typename T> struct IsSame<T, T> : TrueType {}; struct IsSame : FalseType {};
template <typename T>
struct IsSame<T, T> : TrueType {};
template <typename T> struct IsConst : FalseType {}; template <typename T>
template <typename T> struct IsConst<const T> : TrueType {}; struct IsConst : FalseType {};
template <typename T>
struct IsConst<const T> : TrueType {};
template <typename CT, typename T> template <typename CT, typename T>
struct IsMoreConst struct IsMoreConst
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>, : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {}; BoolType<IsConst<CT>::Value >= IsConst<T>::Value>>::Type {};
template <typename T> struct IsPointer : FalseType {}; template <typename T>
template <typename T> struct IsPointer<T*> : TrueType {}; struct IsPointer : FalseType {};
template <typename T>
struct IsPointer<T*> : TrueType {};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// IsBaseOf // IsBaseOf
// //
#if RAPIDJSON_HAS_CXX11_TYPETRAITS #if RAPIDJSON_HAS_CXX11_TYPETRAITS
template <typename B, typename D> struct IsBaseOf template <typename B, typename D>
: BoolType< ::std::is_base_of<B,D>::value> {}; struct IsBaseOf
: BoolType<::std::is_base_of<B, D>::value> {};
#else // simplified version adopted from Boost #else // simplified version adopted from Boost
template<typename B, typename D> struct IsBaseOfImpl { template <typename B, typename D>
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); struct IsBaseOfImpl {
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
typedef char (&Yes)[1]; typedef char (&Yes)[1];
typedef char (&No) [2]; typedef char (&No)[2];
template <typename T> template <typename T>
static Yes Check(const D*, T); static Yes Check(const D*, T);
static No Check(const B*, int); static No Check(const B*, int);
struct Host { struct Host {
operator const B*() const; operator const B*() const;
operator const D*(); operator const D*();
};
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
}; };
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; template <typename B, typename D>
}; struct IsBaseOf
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D>>>::Type {};
template <typename B, typename D> struct IsBaseOf
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS #endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// EnableIf / DisableIf // EnableIf / DisableIf
// //
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; }; template <bool Condition, typename T = void>
template <typename T> struct EnableIfCond<false, T> { /* empty */ }; struct EnableIfCond { typedef T Type; };
template <typename T>
struct EnableIfCond<false, T> { /* empty */
};
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; }; template <bool Condition, typename T = void>
template <typename T> struct DisableIfCond<true, T> { /* empty */ }; struct DisableIfCond { typedef T Type; };
template <typename T>
struct DisableIfCond<true, T> { /* empty */
};
template <typename Condition, typename T = void> template <typename Condition, typename T = void>
struct EnableIf : EnableIfCond<Condition::Value, T> {}; struct EnableIf : EnableIfCond<Condition::Value, T> {};
template <typename Condition, typename T = void> template <typename Condition, typename T = void>
struct DisableIf : DisableIfCond<Condition::Value, T> {}; struct DisableIf : DisableIfCond<Condition::Value, T> {};
// SFINAE helpers // SFINAE helpers
struct SfinaeTag {}; struct SfinaeTag {};
template <typename T> struct RemoveSfinaeTag; template <typename T>
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; }; struct RemoveSfinaeTag;
template <typename T>
struct RemoveSfinaeTag<SfinaeTag& (*)(T)> { typedef T Type; };
#define RAPIDJSON_REMOVEFPTR_(type) \ #define RAPIDJSON_REMOVEFPTR_(type) \
typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag<::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*)type>::Type
< ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
#define RAPIDJSON_ENABLEIF(cond) \ #define RAPIDJSON_ENABLEIF(cond) \
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf<RAPIDJSON_REMOVEFPTR_(cond)>::Type* = NULL
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_DISABLEIF(cond) \ #define RAPIDJSON_DISABLEIF(cond) \
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf<RAPIDJSON_REMOVEFPTR_(cond)>::Type* = NULL
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ #define RAPIDJSON_ENABLEIF_RETURN(cond, returntype) \
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf<RAPIDJSON_REMOVEFPTR_(cond), \
<RAPIDJSON_REMOVEFPTR_(cond), \ RAPIDJSON_REMOVEFPTR_(returntype)>::Type
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ #define RAPIDJSON_DISABLEIF_RETURN(cond, returntype) \
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf<RAPIDJSON_REMOVEFPTR_(cond), \
<RAPIDJSON_REMOVEFPTR_(cond), \ RAPIDJSON_REMOVEFPTR_(returntype)>::Type
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_POW10_ #ifndef RAPIDJSON_POW10_
@ -20,34 +20,34 @@
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
//! Computes integer powers of 10 in double (10.0^n). //! Computes integer powers of 10 in double (10.0^n).
/*! This function uses lookup table for fast and accurate results. /*! This function uses lookup table for fast and accurate results.
\param n non-negative exponent. Must <= 308. \param n non-negative exponent. Must <= 308.
\return 10.0^n \return 10.0^n
*/ */
inline double Pow10(int n) { inline double Pow10(int n) {
static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
1e+0, 1e+0,
1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, 1e+101, 1e+102, 1e+103, 1e+104, 1e+105, 1e+106, 1e+107, 1e+108, 1e+109, 1e+110, 1e+111, 1e+112, 1e+113, 1e+114, 1e+115, 1e+116, 1e+117, 1e+118, 1e+119, 1e+120,
1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, 1e+121, 1e+122, 1e+123, 1e+124, 1e+125, 1e+126, 1e+127, 1e+128, 1e+129, 1e+130, 1e+131, 1e+132, 1e+133, 1e+134, 1e+135, 1e+136, 1e+137, 1e+138, 1e+139, 1e+140,
1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, 1e+141, 1e+142, 1e+143, 1e+144, 1e+145, 1e+146, 1e+147, 1e+148, 1e+149, 1e+150, 1e+151, 1e+152, 1e+153, 1e+154, 1e+155, 1e+156, 1e+157, 1e+158, 1e+159, 1e+160,
1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, 1e+161, 1e+162, 1e+163, 1e+164, 1e+165, 1e+166, 1e+167, 1e+168, 1e+169, 1e+170, 1e+171, 1e+172, 1e+173, 1e+174, 1e+175, 1e+176, 1e+177, 1e+178, 1e+179, 1e+180,
1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, 1e+181, 1e+182, 1e+183, 1e+184, 1e+185, 1e+186, 1e+187, 1e+188, 1e+189, 1e+190, 1e+191, 1e+192, 1e+193, 1e+194, 1e+195, 1e+196, 1e+197, 1e+198, 1e+199, 1e+200,
1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, 1e+201, 1e+202, 1e+203, 1e+204, 1e+205, 1e+206, 1e+207, 1e+208, 1e+209, 1e+210, 1e+211, 1e+212, 1e+213, 1e+214, 1e+215, 1e+216, 1e+217, 1e+218, 1e+219, 1e+220,
1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, 1e+221, 1e+222, 1e+223, 1e+224, 1e+225, 1e+226, 1e+227, 1e+228, 1e+229, 1e+230, 1e+231, 1e+232, 1e+233, 1e+234, 1e+235, 1e+236, 1e+237, 1e+238, 1e+239, 1e+240,
1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, 1e+241, 1e+242, 1e+243, 1e+244, 1e+245, 1e+246, 1e+247, 1e+248, 1e+249, 1e+250, 1e+251, 1e+252, 1e+253, 1e+254, 1e+255, 1e+256, 1e+257, 1e+258, 1e+259, 1e+260,
1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, 1e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1e+267, 1e+268, 1e+269, 1e+270, 1e+271, 1e+272, 1e+273, 1e+274, 1e+275, 1e+276, 1e+277, 1e+278, 1e+279, 1e+280,
1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, 1e+281, 1e+282, 1e+283, 1e+284, 1e+285, 1e+286, 1e+287, 1e+288, 1e+289, 1e+290, 1e+291, 1e+292, 1e+293, 1e+294, 1e+295, 1e+296, 1e+297, 1e+298, 1e+299, 1e+300,
1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 1e+301, 1e+302, 1e+303, 1e+304, 1e+305, 1e+306, 1e+307, 1e+308
}; };
RAPIDJSON_ASSERT(n >= 0 && n <= 308); RAPIDJSON_ASSERT(n >= 0 && n <= 308);
return e[n]; return e[n];
} }
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_STACK_H_ #ifndef RAPIDJSON_INTERNAL_STACK_H_
@ -21,61 +21,34 @@
#if defined(__clang__) #if defined(__clang__)
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(c++98-compat) RAPIDJSON_DIAG_OFF(c++ 98 - compat)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Stack // Stack
//! A type-unsafe stack for storing different types of data. //! A type-unsafe stack for storing different types of data.
/*! \tparam Allocator Allocator for allocating stack memory. /*! \tparam Allocator Allocator for allocating stack memory.
*/ */
template <typename Allocator> template <typename Allocator>
class Stack { class Stack {
public: public:
// Optimization note: Do not allocate memory for stack_ in constructor. // Optimization note: Do not allocate memory for stack_ in constructor.
// Do it lazily when first Push() -> Expand() -> Resize(). // Do it lazily when first Push() -> Expand() -> Resize().
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
} }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
Stack(Stack&& rhs) Stack(Stack&& rhs)
: allocator_(rhs.allocator_), : allocator_(rhs.allocator_),
ownAllocator_(rhs.ownAllocator_), ownAllocator_(rhs.ownAllocator_),
stack_(rhs.stack_), stack_(rhs.stack_),
stackTop_(rhs.stackTop_), stackTop_(rhs.stackTop_),
stackEnd_(rhs.stackEnd_), stackEnd_(rhs.stackEnd_),
initialCapacity_(rhs.initialCapacity_) initialCapacity_(rhs.initialCapacity_) {
{
rhs.allocator_ = 0;
rhs.ownAllocator_ = 0;
rhs.stack_ = 0;
rhs.stackTop_ = 0;
rhs.stackEnd_ = 0;
rhs.initialCapacity_ = 0;
}
#endif
~Stack() {
Destroy();
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
Stack& operator=(Stack&& rhs) {
if (&rhs != this)
{
Destroy();
allocator_ = rhs.allocator_;
ownAllocator_ = rhs.ownAllocator_;
stack_ = rhs.stack_;
stackTop_ = rhs.stackTop_;
stackEnd_ = rhs.stackEnd_;
initialCapacity_ = rhs.initialCapacity_;
rhs.allocator_ = 0; rhs.allocator_ = 0;
rhs.ownAllocator_ = 0; rhs.ownAllocator_ = 0;
rhs.stack_ = 0; rhs.stack_ = 0;
@ -83,144 +56,170 @@ public:
rhs.stackEnd_ = 0; rhs.stackEnd_ = 0;
rhs.initialCapacity_ = 0; rhs.initialCapacity_ = 0;
} }
return *this;
}
#endif #endif
void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { ~Stack() {
internal::Swap(allocator_, rhs.allocator_); Destroy();
internal::Swap(ownAllocator_, rhs.ownAllocator_);
internal::Swap(stack_, rhs.stack_);
internal::Swap(stackTop_, rhs.stackTop_);
internal::Swap(stackEnd_, rhs.stackEnd_);
internal::Swap(initialCapacity_, rhs.initialCapacity_);
}
void Clear() { stackTop_ = stack_; }
void ShrinkToFit() {
if (Empty()) {
// If the stack is empty, completely deallocate the memory.
Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
stack_ = 0;
stackTop_ = 0;
stackEnd_ = 0;
} }
else
Resize(GetSize());
}
// Optimization note: try to minimize the size of this function for force inline. #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function. Stack& operator=(Stack&& rhs) {
template<typename T> if (&rhs != this) {
RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { Destroy();
// Expand the stack if needed
if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
Expand<T>(count);
}
template<typename T> allocator_ = rhs.allocator_;
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { ownAllocator_ = rhs.ownAllocator_;
Reserve<T>(count); stack_ = rhs.stack_;
return PushUnsafe<T>(count); stackTop_ = rhs.stackTop_;
} stackEnd_ = rhs.stackEnd_;
initialCapacity_ = rhs.initialCapacity_;
template<typename T> rhs.allocator_ = 0;
RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { rhs.ownAllocator_ = 0;
RAPIDJSON_ASSERT(stackTop_); rhs.stack_ = 0;
RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_)); rhs.stackTop_ = 0;
T* ret = reinterpret_cast<T*>(stackTop_); rhs.stackEnd_ = 0;
stackTop_ += sizeof(T) * count; rhs.initialCapacity_ = 0;
return ret; }
} return *this;
template<typename T>
T* Pop(size_t count) {
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
stackTop_ -= count * sizeof(T);
return reinterpret_cast<T*>(stackTop_);
}
template<typename T>
T* Top() {
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
}
template<typename T>
const T* Top() const {
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
}
template<typename T>
T* End() { return reinterpret_cast<T*>(stackTop_); }
template<typename T>
const T* End() const { return reinterpret_cast<T*>(stackTop_); }
template<typename T>
T* Bottom() { return reinterpret_cast<T*>(stack_); }
template<typename T>
const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
bool HasAllocator() const {
return allocator_ != 0;
}
Allocator& GetAllocator() {
RAPIDJSON_ASSERT(allocator_);
return *allocator_;
}
bool Empty() const { return stackTop_ == stack_; }
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
private:
template<typename T>
void Expand(size_t count) {
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
size_t newCapacity;
if (stack_ == 0) {
if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
newCapacity = initialCapacity_;
} else {
newCapacity = GetCapacity();
newCapacity += (newCapacity + 1) / 2;
} }
size_t newSize = GetSize() + sizeof(T) * count; #endif
if (newCapacity < newSize)
newCapacity = newSize;
Resize(newCapacity); void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
} internal::Swap(allocator_, rhs.allocator_);
internal::Swap(ownAllocator_, rhs.ownAllocator_);
internal::Swap(stack_, rhs.stack_);
internal::Swap(stackTop_, rhs.stackTop_);
internal::Swap(stackEnd_, rhs.stackEnd_);
internal::Swap(initialCapacity_, rhs.initialCapacity_);
}
void Resize(size_t newCapacity) { void Clear() { stackTop_ = stack_; }
const size_t size = GetSize(); // Backup the current size
stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
stackTop_ = stack_ + size;
stackEnd_ = stack_ + newCapacity;
}
void Destroy() { void ShrinkToFit() {
Allocator::Free(stack_); if (Empty()) {
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack // If the stack is empty, completely deallocate the memory.
} Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
stack_ = 0;
stackTop_ = 0;
stackEnd_ = 0;
}
else
Resize(GetSize());
}
// Prohibit copy constructor & assignment operator. // Optimization note: try to minimize the size of this function for force inline.
Stack(const Stack&); // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
Stack& operator=(const Stack&); template <typename T>
RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
// Expand the stack if needed
if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
Expand<T>(count);
}
Allocator* allocator_; template <typename T>
Allocator* ownAllocator_; RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
char *stack_; Reserve<T>(count);
char *stackTop_; return PushUnsafe<T>(count);
char *stackEnd_; }
size_t initialCapacity_;
}; template <typename T>
RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
RAPIDJSON_ASSERT(stackTop_);
RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
T* ret = reinterpret_cast<T*>(stackTop_);
stackTop_ += sizeof(T) * count;
return ret;
}
template <typename T>
T* Pop(size_t count) {
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
stackTop_ -= count * sizeof(T);
return reinterpret_cast<T*>(stackTop_);
}
template <typename T>
T* Top() {
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
}
template <typename T>
const T* Top() const {
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
}
template <typename T>
T* End() { return reinterpret_cast<T*>(stackTop_); }
template <typename T>
const T* End() const { return reinterpret_cast<T*>(stackTop_); }
template <typename T>
T* Bottom() { return reinterpret_cast<T*>(stack_); }
template <typename T>
const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
bool HasAllocator() const {
return allocator_ != 0;
}
Allocator& GetAllocator() {
RAPIDJSON_ASSERT(allocator_);
return *allocator_;
}
bool Empty() const { return stackTop_ == stack_; }
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
private:
template <typename T>
void Expand(size_t count) {
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
size_t newCapacity;
if (stack_ == 0) {
if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
newCapacity = initialCapacity_;
}
else {
newCapacity = GetCapacity();
newCapacity += (newCapacity + 1) / 2;
}
size_t newSize = GetSize() + sizeof(T) * count;
if (newCapacity < newSize)
newCapacity = newSize;
Resize(newCapacity);
}
void Resize(size_t newCapacity) {
const size_t size = GetSize(); // Backup the current size
stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
stackTop_ = stack_ + size;
stackEnd_ = stack_ + newCapacity;
}
void Destroy() {
Allocator::Free(stack_);
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
}
// Prohibit copy constructor & assignment operator.
Stack(const Stack&);
Stack& operator=(const Stack&);
Allocator* allocator_;
Allocator* ownAllocator_;
char* stack_;
char* stackTop_;
char* stackEnd_;
size_t initialCapacity_;
};
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
@ -21,47 +21,47 @@
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
//! Custom strlen() which works on different character types. //! Custom strlen() which works on different character types.
/*! \tparam Ch Character type (e.g. char, wchar_t, short) /*! \tparam Ch Character type (e.g. char, wchar_t, short)
\param s Null-terminated input string. \param s Null-terminated input string.
\return Number of characters in the string. \return Number of characters in the string.
\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
*/ */
template <typename Ch> template <typename Ch>
inline SizeType StrLen(const Ch* s) { inline SizeType StrLen(const Ch* s) {
RAPIDJSON_ASSERT(s != 0); RAPIDJSON_ASSERT(s != 0);
const Ch* p = s; const Ch* p = s;
while (*p) ++p; while (*p) ++p;
return SizeType(p - s); return SizeType(p - s);
} }
template <> template <>
inline SizeType StrLen(const char* s) { inline SizeType StrLen(const char* s) {
return SizeType(std::strlen(s)); return SizeType(std::strlen(s));
} }
template <> template <>
inline SizeType StrLen(const wchar_t* s) { inline SizeType StrLen(const wchar_t* s) {
return SizeType(std::wcslen(s)); return SizeType(std::wcslen(s));
} }
//! Returns number of code points in a encoded string. //! Returns number of code points in a encoded string.
template<typename Encoding> template <typename Encoding>
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
RAPIDJSON_ASSERT(s != 0); RAPIDJSON_ASSERT(s != 0);
RAPIDJSON_ASSERT(outCount != 0); RAPIDJSON_ASSERT(outCount != 0);
GenericStringStream<Encoding> is(s); GenericStringStream<Encoding> is(s);
const typename Encoding::Ch* end = s + length; const typename Encoding::Ch* end = s + length;
SizeType count = 0; SizeType count = 0;
while (is.src_ < end) { while (is.src_ < end) {
unsigned codepoint; unsigned codepoint;
if (!Encoding::Decode(is, &codepoint)) if (!Encoding::Decode(is, &codepoint))
return false; return false;
count++; count++;
}
*outCount = count;
return true;
} }
*outCount = count;
return true;
}
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_STRTOD_ #ifndef RAPIDJSON_STRTOD_
@ -25,264 +25,264 @@
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
inline double FastPath(double significand, int exp) { inline double FastPath(double significand, int exp) {
if (exp < -308) if (exp < -308)
return 0.0; return 0.0;
else if (exp >= 0) else if (exp >= 0)
return significand * internal::Pow10(exp); return significand * internal::Pow10(exp);
else
return significand / internal::Pow10(-exp);
}
inline double StrtodNormalPrecision(double d, int p) {
if (p < -308) {
// Prevent expSum < -308, making Pow10(p) = 0
d = FastPath(d, -308);
d = FastPath(d, p + 308);
}
else
d = FastPath(d, p);
return d;
}
template <typename T>
inline T Min3(T a, T b, T c) {
T m = a;
if (m > b) m = b;
if (m > c) m = c;
return m;
}
inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
const Double db(b);
const uint64_t bInt = db.IntegerSignificand();
const int bExp = db.IntegerExponent();
const int hExp = bExp - 1;
int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
// Adjust for decimal exponent
if (dExp >= 0) {
dS_Exp2 += dExp;
dS_Exp5 += dExp;
}
else {
bS_Exp2 -= dExp;
bS_Exp5 -= dExp;
hS_Exp2 -= dExp;
hS_Exp5 -= dExp;
}
// Adjust for binary exponent
if (bExp >= 0)
bS_Exp2 += bExp;
else {
dS_Exp2 -= bExp;
hS_Exp2 -= bExp;
}
// Adjust for half ulp exponent
if (hExp >= 0)
hS_Exp2 += hExp;
else {
dS_Exp2 -= hExp;
bS_Exp2 -= hExp;
}
// Remove common power of two factor from all three scaled values
int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
dS_Exp2 -= common_Exp2;
bS_Exp2 -= common_Exp2;
hS_Exp2 -= common_Exp2;
BigInteger dS = d;
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
BigInteger bS(bInt);
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
BigInteger hS(1);
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
BigInteger delta(0);
dS.Difference(bS, &delta);
return delta.Compare(hS);
}
inline bool StrtodFast(double d, int p, double* result) {
// Use fast path for string-to-double conversion if possible
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
if (p > 22 && p < 22 + 16) {
// Fast Path Cases In Disguise
d *= internal::Pow10(p - 22);
p = 22;
}
if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
*result = FastPath(d, p);
return true;
}
else
return false;
}
// Compute an approximation and see if it is within 1/2 ULP
inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) {
uint64_t significand = 0;
int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
for (; i < dLen; i++) {
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
break;
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
}
if (i < dLen && decimals[i] >= '5') // Rounding
significand++;
int remaining = dLen - i;
const int kUlpShift = 3;
const int kUlp = 1 << kUlpShift;
int64_t error = (remaining == 0) ? 0 : kUlp / 2;
DiyFp v(significand, 0);
v = v.Normalize();
error <<= -v.e;
dExp += remaining;
int actualExp;
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
if (actualExp != dExp) {
static const DiyFp kPow10[] = {
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3
DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4
DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7
};
int adjustment = dExp - actualExp;
RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8);
v = v * kPow10[adjustment - 1];
if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit
error += kUlp / 2;
}
v = v * cachedPower;
error += kUlp + (error == 0 ? 0 : 1);
const int oldExp = v.e;
v = v.Normalize();
error <<= oldExp - v.e;
const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
int precisionSize = 64 - effectiveSignificandSize;
if (precisionSize + kUlpShift >= 64) {
int scaleExp = (precisionSize + kUlpShift) - 63;
v.f >>= scaleExp;
v.e += scaleExp;
error = (error >> scaleExp) + 1 + kUlp;
precisionSize -= scaleExp;
}
DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
rounded.f++;
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
rounded.f >>= 1;
rounded.e++;
}
}
*result = rounded.ToDouble();
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
}
inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) {
RAPIDJSON_ASSERT(dLen >= 0);
const BigInteger dInt(decimals, static_cast<unsigned>(dLen));
Double a(approx);
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
if (cmp < 0)
return a.Value(); // within half ULP
else if (cmp == 0) {
// Round towards even
if (a.Significand() & 1)
return a.NextPositiveDouble();
else else
return a.Value(); return significand / internal::Pow10(-exp);
}
else // adjustment
return a.NextPositiveDouble();
}
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
RAPIDJSON_ASSERT(d >= 0.0);
RAPIDJSON_ASSERT(length >= 1);
double result = 0.0;
if (StrtodFast(d, p, &result))
return result;
RAPIDJSON_ASSERT(length <= INT_MAX);
int dLen = static_cast<int>(length);
RAPIDJSON_ASSERT(length >= decimalPosition);
RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX);
int dExpAdjust = static_cast<int>(length - decimalPosition);
RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust);
int dExp = exp - dExpAdjust;
// Make sure length+dExp does not overflow
RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen);
// Trim leading zeros
while (dLen > 0 && *decimals == '0') {
dLen--;
decimals++;
} }
// Trim trailing zeros inline double StrtodNormalPrecision(double d, int p) {
while (dLen > 0 && decimals[dLen - 1] == '0') { if (p < -308) {
dLen--; // Prevent expSum < -308, making Pow10(p) = 0
dExp++; d = FastPath(d, -308);
d = FastPath(d, p + 308);
}
else
d = FastPath(d, p);
return d;
} }
if (dLen == 0) { // Buffer only contains zeros. template <typename T>
return 0.0; inline T Min3(T a, T b, T c) {
T m = a;
if (m > b) m = b;
if (m > c) m = c;
return m;
} }
// Trim right-most digits inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
const int kMaxDecimalDigit = 767 + 1; const Double db(b);
if (dLen > kMaxDecimalDigit) { const uint64_t bInt = db.IntegerSignificand();
dExp += dLen - kMaxDecimalDigit; const int bExp = db.IntegerExponent();
dLen = kMaxDecimalDigit; const int hExp = bExp - 1;
int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
// Adjust for decimal exponent
if (dExp >= 0) {
dS_Exp2 += dExp;
dS_Exp5 += dExp;
}
else {
bS_Exp2 -= dExp;
bS_Exp5 -= dExp;
hS_Exp2 -= dExp;
hS_Exp5 -= dExp;
}
// Adjust for binary exponent
if (bExp >= 0)
bS_Exp2 += bExp;
else {
dS_Exp2 -= bExp;
hS_Exp2 -= bExp;
}
// Adjust for half ulp exponent
if (hExp >= 0)
hS_Exp2 += hExp;
else {
dS_Exp2 -= hExp;
bS_Exp2 -= hExp;
}
// Remove common power of two factor from all three scaled values
int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
dS_Exp2 -= common_Exp2;
bS_Exp2 -= common_Exp2;
hS_Exp2 -= common_Exp2;
BigInteger dS = d;
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
BigInteger bS(bInt);
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
BigInteger hS(1);
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
BigInteger delta(0);
dS.Difference(bS, &delta);
return delta.Compare(hS);
} }
// If too small, underflow to zero. inline bool StrtodFast(double d, int p, double* result) {
// Any x <= 10^-324 is interpreted as zero. // Use fast path for string-to-double conversion if possible
if (dLen + dExp <= -324) // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
return 0.0; if (p > 22 && p < 22 + 16) {
// Fast Path Cases In Disguise
d *= internal::Pow10(p - 22);
p = 22;
}
// If too large, overflow to infinity. if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
// Any x >= 10^309 is interpreted as +infinity. *result = FastPath(d, p);
if (dLen + dExp > 309) return true;
return std::numeric_limits<double>::infinity(); }
else
return false;
}
if (StrtodDiyFp(decimals, dLen, dExp, &result)) // Compute an approximation and see if it is within 1/2 ULP
return result; inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) {
uint64_t significand = 0;
int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
for (; i < dLen; i++) {
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
break;
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
}
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison if (i < dLen && decimals[i] >= '5') // Rounding
return StrtodBigInteger(result, decimals, dLen, dExp); significand++;
}
int remaining = dLen - i;
const int kUlpShift = 3;
const int kUlp = 1 << kUlpShift;
int64_t error = (remaining == 0) ? 0 : kUlp / 2;
DiyFp v(significand, 0);
v = v.Normalize();
error <<= -v.e;
dExp += remaining;
int actualExp;
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
if (actualExp != dExp) {
static const DiyFp kPow10[] = {
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3
DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4
DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7
};
int adjustment = dExp - actualExp;
RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8);
v = v * kPow10[adjustment - 1];
if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit
error += kUlp / 2;
}
v = v * cachedPower;
error += kUlp + (error == 0 ? 0 : 1);
const int oldExp = v.e;
v = v.Normalize();
error <<= oldExp - v.e;
const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
int precisionSize = 64 - effectiveSignificandSize;
if (precisionSize + kUlpShift >= 64) {
int scaleExp = (precisionSize + kUlpShift) - 63;
v.f >>= scaleExp;
v.e += scaleExp;
error = (error >> scaleExp) + 1 + kUlp;
precisionSize -= scaleExp;
}
DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
rounded.f++;
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
rounded.f >>= 1;
rounded.e++;
}
}
*result = rounded.ToDouble();
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
}
inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) {
RAPIDJSON_ASSERT(dLen >= 0);
const BigInteger dInt(decimals, static_cast<unsigned>(dLen));
Double a(approx);
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
if (cmp < 0)
return a.Value(); // within half ULP
else if (cmp == 0) {
// Round towards even
if (a.Significand() & 1)
return a.NextPositiveDouble();
else
return a.Value();
}
else // adjustment
return a.NextPositiveDouble();
}
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
RAPIDJSON_ASSERT(d >= 0.0);
RAPIDJSON_ASSERT(length >= 1);
double result = 0.0;
if (StrtodFast(d, p, &result))
return result;
RAPIDJSON_ASSERT(length <= INT_MAX);
int dLen = static_cast<int>(length);
RAPIDJSON_ASSERT(length >= decimalPosition);
RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX);
int dExpAdjust = static_cast<int>(length - decimalPosition);
RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust);
int dExp = exp - dExpAdjust;
// Make sure length+dExp does not overflow
RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen);
// Trim leading zeros
while (dLen > 0 && *decimals == '0') {
dLen--;
decimals++;
}
// Trim trailing zeros
while (dLen > 0 && decimals[dLen - 1] == '0') {
dLen--;
dExp++;
}
if (dLen == 0) { // Buffer only contains zeros.
return 0.0;
}
// Trim right-most digits
const int kMaxDecimalDigit = 767 + 1;
if (dLen > kMaxDecimalDigit) {
dExp += dLen - kMaxDecimalDigit;
dLen = kMaxDecimalDigit;
}
// If too small, underflow to zero.
// Any x <= 10^-324 is interpreted as zero.
if (dLen + dExp <= -324)
return 0.0;
// If too large, overflow to infinity.
// Any x >= 10^309 is interpreted as +infinity.
if (dLen + dExp > 309)
return std::numeric_limits<double>::infinity();
if (StrtodDiyFp(decimals, dLen, dExp, &result))
return result;
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
return StrtodBigInteger(result, decimals, dLen, dExp);
}
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View File

@ -19,22 +19,22 @@
#if defined(__clang__) #if defined(__clang__)
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(c++98-compat) RAPIDJSON_DIAG_OFF(c++ 98 - compat)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
//! Custom swap() to avoid dependency on C++ <algorithm> header //! Custom swap() to avoid dependency on C++ <algorithm> header
/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
\note This has the same semantics as std::swap(). \note This has the same semantics as std::swap().
*/ */
template <typename T> template <typename T>
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
T tmp = a; T tmp = a;
a = b; a = b;
b = tmp; b = tmp;
} }
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ISTREAMWRAPPER_H_ #ifndef RAPIDJSON_ISTREAMWRAPPER_H_
@ -44,7 +44,7 @@ RAPIDJSON_NAMESPACE_BEGIN
\tparam StreamType Class derived from \c std::basic_istream. \tparam StreamType Class derived from \c std::basic_istream.
*/ */
template <typename StreamType> template <typename StreamType>
class BasicIStreamWrapper { class BasicIStreamWrapper {
public: public:
@ -54,7 +54,7 @@ public:
/*! /*!
\param stream stream opened for read. \param stream stream opened for read.
*/ */
BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { BasicIStreamWrapper(StreamType& stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
Read(); Read();
} }
@ -64,20 +64,30 @@ public:
\param buffer user-supplied buffer. \param buffer user-supplied buffer.
\param bufferSize size of buffer in bytes. Must >=4 bytes. \param bufferSize size of buffer in bytes. Must >=4 bytes.
*/ */
BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { BasicIStreamWrapper(StreamType& stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
RAPIDJSON_ASSERT(bufferSize >= 4); RAPIDJSON_ASSERT(bufferSize >= 4);
Read(); Read();
} }
Ch Peek() const { return *current_; } Ch Peek() const { return *current_; }
Ch Take() { Ch c = *current_; Read(); return c; } Ch Take() {
Ch c = *current_;
Read();
return c;
}
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); } size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
// Not implemented // Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); } void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() {
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } RAPIDJSON_ASSERT(false);
return 0;
}
size_t PutEnd(Ch*) {
RAPIDJSON_ASSERT(false);
return 0;
}
// For encoding detection only. // For encoding detection only.
const Ch* Peek4() const { const Ch* Peek4() const {
@ -106,13 +116,13 @@ private:
} }
} }
StreamType &stream_; StreamType& stream_;
Ch peekBuffer_[4], *buffer_; Ch peekBuffer_[4], *buffer_;
size_t bufferSize_; size_t bufferSize_;
Ch *bufferLast_; Ch* bufferLast_;
Ch *current_; Ch* current_;
size_t readCount_; size_t readCount_;
size_t count_; //!< Number of characters read size_t count_; //!< Number of characters read
bool eof_; bool eof_;
}; };

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_MEMORYBUFFER_H_ #ifndef RAPIDJSON_MEMORYBUFFER_H_
@ -60,7 +60,7 @@ struct GenericMemoryBuffer {
typedef GenericMemoryBuffer<> MemoryBuffer; typedef GenericMemoryBuffer<> MemoryBuffer;
//! Implement specialized version of PutN() with memset() for better performance. //! Implement specialized version of PutN() with memset() for better performance.
template<> template <>
inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c)); std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
} }

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_MEMORYSTREAM_H_ #ifndef RAPIDJSON_MEMORYSTREAM_H_
@ -19,8 +19,8 @@
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(unreachable - code)
RAPIDJSON_DIAG_OFF(missing-noreturn) RAPIDJSON_DIAG_OFF(missing - noreturn)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -40,26 +40,32 @@ RAPIDJSON_NAMESPACE_BEGIN
struct MemoryStream { struct MemoryStream {
typedef char Ch; // byte typedef char Ch; // byte
MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} MemoryStream(const Ch* src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; }
Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; }
size_t Tell() const { return static_cast<size_t>(src_ - begin_); } size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() {
RAPIDJSON_ASSERT(false);
return 0;
}
void Put(Ch) { RAPIDJSON_ASSERT(false); } void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) {
RAPIDJSON_ASSERT(false);
return 0;
}
// For encoding detection only. // For encoding detection only.
const Ch* Peek4() const { const Ch* Peek4() const {
return Tell() + 4 <= size_ ? src_ : 0; return Tell() + 4 <= size_ ? src_ : 0;
} }
const Ch* src_; //!< Current read position. const Ch* src_; //!< Current read position.
const Ch* begin_; //!< Original head of the string. const Ch* begin_; //!< Original head of the string.
const Ch* end_; //!< End of stream. const Ch* end_; //!< End of stream.
size_t size_; //!< Size of the stream. size_t size_; //!< Size of the stream.
}; };
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View File

@ -1,37 +1,37 @@
// ISO C9x compliant inttypes.h for Microsoft Visual Studio // ISO C9x compliant inttypes.h for Microsoft Visual Studio
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
// //
// Copyright (c) 2006-2013 Alexander Chemeris // Copyright (c) 2006-2013 Alexander Chemeris
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met: // modification, are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright // 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the // notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution. // documentation and/or other materials provided with the distribution.
// //
// 3. Neither the name of the product nor the names of its contributors may // 3. Neither the name of the product nor the names of its contributors may
// be used to endorse or promote products derived from this software // be used to endorse or promote products derived from this software
// without specific prior written permission. // without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// The above software in this distribution may have been modified by // The above software in this distribution may have been modified by
// THL A29 Limited ("Tencent Modifications"). // THL A29 Limited ("Tencent Modifications").
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. // All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
#ifndef _MSC_VER // [ #ifndef _MSC_VER // [
@ -55,8 +55,8 @@
// 7.8 Format conversion of integer types // 7.8 Format conversion of integer types
typedef struct { typedef struct {
intmax_t quot; intmax_t quot;
intmax_t rem; intmax_t rem;
} imaxdiv_t; } imaxdiv_t;
// 7.8.1 Macros for format specifiers // 7.8.1 Macros for format specifiers
@ -64,212 +64,212 @@ typedef struct {
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 #if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
// The fprintf macros for signed integers are: // The fprintf macros for signed integers are:
#define PRId8 "d" #define PRId8 "d"
#define PRIi8 "i" #define PRIi8 "i"
#define PRIdLEAST8 "d" #define PRIdLEAST8 "d"
#define PRIiLEAST8 "i" #define PRIiLEAST8 "i"
#define PRIdFAST8 "d" #define PRIdFAST8 "d"
#define PRIiFAST8 "i" #define PRIiFAST8 "i"
#define PRId16 "hd" #define PRId16 "hd"
#define PRIi16 "hi" #define PRIi16 "hi"
#define PRIdLEAST16 "hd" #define PRIdLEAST16 "hd"
#define PRIiLEAST16 "hi" #define PRIiLEAST16 "hi"
#define PRIdFAST16 "hd" #define PRIdFAST16 "hd"
#define PRIiFAST16 "hi" #define PRIiFAST16 "hi"
#define PRId32 "I32d" #define PRId32 "I32d"
#define PRIi32 "I32i" #define PRIi32 "I32i"
#define PRIdLEAST32 "I32d" #define PRIdLEAST32 "I32d"
#define PRIiLEAST32 "I32i" #define PRIiLEAST32 "I32i"
#define PRIdFAST32 "I32d" #define PRIdFAST32 "I32d"
#define PRIiFAST32 "I32i" #define PRIiFAST32 "I32i"
#define PRId64 "I64d" #define PRId64 "I64d"
#define PRIi64 "I64i" #define PRIi64 "I64i"
#define PRIdLEAST64 "I64d" #define PRIdLEAST64 "I64d"
#define PRIiLEAST64 "I64i" #define PRIiLEAST64 "I64i"
#define PRIdFAST64 "I64d" #define PRIdFAST64 "I64d"
#define PRIiFAST64 "I64i" #define PRIiFAST64 "I64i"
#define PRIdMAX "I64d" #define PRIdMAX "I64d"
#define PRIiMAX "I64i" #define PRIiMAX "I64i"
#define PRIdPTR "Id" #define PRIdPTR "Id"
#define PRIiPTR "Ii" #define PRIiPTR "Ii"
// The fprintf macros for unsigned integers are: // The fprintf macros for unsigned integers are:
#define PRIo8 "o" #define PRIo8 "o"
#define PRIu8 "u" #define PRIu8 "u"
#define PRIx8 "x" #define PRIx8 "x"
#define PRIX8 "X" #define PRIX8 "X"
#define PRIoLEAST8 "o" #define PRIoLEAST8 "o"
#define PRIuLEAST8 "u" #define PRIuLEAST8 "u"
#define PRIxLEAST8 "x" #define PRIxLEAST8 "x"
#define PRIXLEAST8 "X" #define PRIXLEAST8 "X"
#define PRIoFAST8 "o" #define PRIoFAST8 "o"
#define PRIuFAST8 "u" #define PRIuFAST8 "u"
#define PRIxFAST8 "x" #define PRIxFAST8 "x"
#define PRIXFAST8 "X" #define PRIXFAST8 "X"
#define PRIo16 "ho" #define PRIo16 "ho"
#define PRIu16 "hu" #define PRIu16 "hu"
#define PRIx16 "hx" #define PRIx16 "hx"
#define PRIX16 "hX" #define PRIX16 "hX"
#define PRIoLEAST16 "ho" #define PRIoLEAST16 "ho"
#define PRIuLEAST16 "hu" #define PRIuLEAST16 "hu"
#define PRIxLEAST16 "hx" #define PRIxLEAST16 "hx"
#define PRIXLEAST16 "hX" #define PRIXLEAST16 "hX"
#define PRIoFAST16 "ho" #define PRIoFAST16 "ho"
#define PRIuFAST16 "hu" #define PRIuFAST16 "hu"
#define PRIxFAST16 "hx" #define PRIxFAST16 "hx"
#define PRIXFAST16 "hX" #define PRIXFAST16 "hX"
#define PRIo32 "I32o" #define PRIo32 "I32o"
#define PRIu32 "I32u" #define PRIu32 "I32u"
#define PRIx32 "I32x" #define PRIx32 "I32x"
#define PRIX32 "I32X" #define PRIX32 "I32X"
#define PRIoLEAST32 "I32o" #define PRIoLEAST32 "I32o"
#define PRIuLEAST32 "I32u" #define PRIuLEAST32 "I32u"
#define PRIxLEAST32 "I32x" #define PRIxLEAST32 "I32x"
#define PRIXLEAST32 "I32X" #define PRIXLEAST32 "I32X"
#define PRIoFAST32 "I32o" #define PRIoFAST32 "I32o"
#define PRIuFAST32 "I32u" #define PRIuFAST32 "I32u"
#define PRIxFAST32 "I32x" #define PRIxFAST32 "I32x"
#define PRIXFAST32 "I32X" #define PRIXFAST32 "I32X"
#define PRIo64 "I64o" #define PRIo64 "I64o"
#define PRIu64 "I64u" #define PRIu64 "I64u"
#define PRIx64 "I64x" #define PRIx64 "I64x"
#define PRIX64 "I64X" #define PRIX64 "I64X"
#define PRIoLEAST64 "I64o" #define PRIoLEAST64 "I64o"
#define PRIuLEAST64 "I64u" #define PRIuLEAST64 "I64u"
#define PRIxLEAST64 "I64x" #define PRIxLEAST64 "I64x"
#define PRIXLEAST64 "I64X" #define PRIXLEAST64 "I64X"
#define PRIoFAST64 "I64o" #define PRIoFAST64 "I64o"
#define PRIuFAST64 "I64u" #define PRIuFAST64 "I64u"
#define PRIxFAST64 "I64x" #define PRIxFAST64 "I64x"
#define PRIXFAST64 "I64X" #define PRIXFAST64 "I64X"
#define PRIoMAX "I64o" #define PRIoMAX "I64o"
#define PRIuMAX "I64u" #define PRIuMAX "I64u"
#define PRIxMAX "I64x" #define PRIxMAX "I64x"
#define PRIXMAX "I64X" #define PRIXMAX "I64X"
#define PRIoPTR "Io" #define PRIoPTR "Io"
#define PRIuPTR "Iu" #define PRIuPTR "Iu"
#define PRIxPTR "Ix" #define PRIxPTR "Ix"
#define PRIXPTR "IX" #define PRIXPTR "IX"
// The fscanf macros for signed integers are: // The fscanf macros for signed integers are:
#define SCNd8 "d" #define SCNd8 "d"
#define SCNi8 "i" #define SCNi8 "i"
#define SCNdLEAST8 "d" #define SCNdLEAST8 "d"
#define SCNiLEAST8 "i" #define SCNiLEAST8 "i"
#define SCNdFAST8 "d" #define SCNdFAST8 "d"
#define SCNiFAST8 "i" #define SCNiFAST8 "i"
#define SCNd16 "hd" #define SCNd16 "hd"
#define SCNi16 "hi" #define SCNi16 "hi"
#define SCNdLEAST16 "hd" #define SCNdLEAST16 "hd"
#define SCNiLEAST16 "hi" #define SCNiLEAST16 "hi"
#define SCNdFAST16 "hd" #define SCNdFAST16 "hd"
#define SCNiFAST16 "hi" #define SCNiFAST16 "hi"
#define SCNd32 "ld" #define SCNd32 "ld"
#define SCNi32 "li" #define SCNi32 "li"
#define SCNdLEAST32 "ld" #define SCNdLEAST32 "ld"
#define SCNiLEAST32 "li" #define SCNiLEAST32 "li"
#define SCNdFAST32 "ld" #define SCNdFAST32 "ld"
#define SCNiFAST32 "li" #define SCNiFAST32 "li"
#define SCNd64 "I64d" #define SCNd64 "I64d"
#define SCNi64 "I64i" #define SCNi64 "I64i"
#define SCNdLEAST64 "I64d" #define SCNdLEAST64 "I64d"
#define SCNiLEAST64 "I64i" #define SCNiLEAST64 "I64i"
#define SCNdFAST64 "I64d" #define SCNdFAST64 "I64d"
#define SCNiFAST64 "I64i" #define SCNiFAST64 "I64i"
#define SCNdMAX "I64d" #define SCNdMAX "I64d"
#define SCNiMAX "I64i" #define SCNiMAX "I64i"
#ifdef _WIN64 // [ #ifdef _WIN64 // [
# define SCNdPTR "I64d" #define SCNdPTR "I64d"
# define SCNiPTR "I64i" #define SCNiPTR "I64i"
#else // _WIN64 ][ #else // _WIN64 ][
# define SCNdPTR "ld" #define SCNdPTR "ld"
# define SCNiPTR "li" #define SCNiPTR "li"
#endif // _WIN64 ] #endif // _WIN64 ]
// The fscanf macros for unsigned integers are: // The fscanf macros for unsigned integers are:
#define SCNo8 "o" #define SCNo8 "o"
#define SCNu8 "u" #define SCNu8 "u"
#define SCNx8 "x" #define SCNx8 "x"
#define SCNX8 "X" #define SCNX8 "X"
#define SCNoLEAST8 "o" #define SCNoLEAST8 "o"
#define SCNuLEAST8 "u" #define SCNuLEAST8 "u"
#define SCNxLEAST8 "x" #define SCNxLEAST8 "x"
#define SCNXLEAST8 "X" #define SCNXLEAST8 "X"
#define SCNoFAST8 "o" #define SCNoFAST8 "o"
#define SCNuFAST8 "u" #define SCNuFAST8 "u"
#define SCNxFAST8 "x" #define SCNxFAST8 "x"
#define SCNXFAST8 "X" #define SCNXFAST8 "X"
#define SCNo16 "ho" #define SCNo16 "ho"
#define SCNu16 "hu" #define SCNu16 "hu"
#define SCNx16 "hx" #define SCNx16 "hx"
#define SCNX16 "hX" #define SCNX16 "hX"
#define SCNoLEAST16 "ho" #define SCNoLEAST16 "ho"
#define SCNuLEAST16 "hu" #define SCNuLEAST16 "hu"
#define SCNxLEAST16 "hx" #define SCNxLEAST16 "hx"
#define SCNXLEAST16 "hX" #define SCNXLEAST16 "hX"
#define SCNoFAST16 "ho" #define SCNoFAST16 "ho"
#define SCNuFAST16 "hu" #define SCNuFAST16 "hu"
#define SCNxFAST16 "hx" #define SCNxFAST16 "hx"
#define SCNXFAST16 "hX" #define SCNXFAST16 "hX"
#define SCNo32 "lo" #define SCNo32 "lo"
#define SCNu32 "lu" #define SCNu32 "lu"
#define SCNx32 "lx" #define SCNx32 "lx"
#define SCNX32 "lX" #define SCNX32 "lX"
#define SCNoLEAST32 "lo" #define SCNoLEAST32 "lo"
#define SCNuLEAST32 "lu" #define SCNuLEAST32 "lu"
#define SCNxLEAST32 "lx" #define SCNxLEAST32 "lx"
#define SCNXLEAST32 "lX" #define SCNXLEAST32 "lX"
#define SCNoFAST32 "lo" #define SCNoFAST32 "lo"
#define SCNuFAST32 "lu" #define SCNuFAST32 "lu"
#define SCNxFAST32 "lx" #define SCNxFAST32 "lx"
#define SCNXFAST32 "lX" #define SCNXFAST32 "lX"
#define SCNo64 "I64o" #define SCNo64 "I64o"
#define SCNu64 "I64u" #define SCNu64 "I64u"
#define SCNx64 "I64x" #define SCNx64 "I64x"
#define SCNX64 "I64X" #define SCNX64 "I64X"
#define SCNoLEAST64 "I64o" #define SCNoLEAST64 "I64o"
#define SCNuLEAST64 "I64u" #define SCNuLEAST64 "I64u"
#define SCNxLEAST64 "I64x" #define SCNxLEAST64 "I64x"
#define SCNXLEAST64 "I64X" #define SCNXLEAST64 "I64X"
#define SCNoFAST64 "I64o" #define SCNoFAST64 "I64o"
#define SCNuFAST64 "I64u" #define SCNuFAST64 "I64u"
#define SCNxFAST64 "I64x" #define SCNxFAST64 "I64x"
#define SCNXFAST64 "I64X" #define SCNXFAST64 "I64X"
#define SCNoMAX "I64o" #define SCNoMAX "I64o"
#define SCNuMAX "I64u" #define SCNuMAX "I64u"
#define SCNxMAX "I64x" #define SCNxMAX "I64x"
#define SCNXMAX "I64X" #define SCNXMAX "I64X"
#ifdef _WIN64 // [ #ifdef _WIN64 // [
# define SCNoPTR "I64o" #define SCNoPTR "I64o"
# define SCNuPTR "I64u" #define SCNuPTR "I64u"
# define SCNxPTR "I64x" #define SCNxPTR "I64x"
# define SCNXPTR "I64X" #define SCNXPTR "I64X"
#else // _WIN64 ][ #else // _WIN64 ][
# define SCNoPTR "lo" #define SCNoPTR "lo"
# define SCNuPTR "lu" #define SCNuPTR "lu"
# define SCNxPTR "lx" #define SCNxPTR "lx"
# define SCNXPTR "lX" #define SCNXPTR "lX"
#endif // _WIN64 ] #endif // _WIN64 ]
#endif // __STDC_FORMAT_MACROS ] #endif // __STDC_FORMAT_MACROS ]
@ -284,23 +284,22 @@ typedef struct {
// in %MSVC.NET%\crt\src\div.c // in %MSVC.NET%\crt\src\div.c
#ifdef STATIC_IMAXDIV // [ #ifdef STATIC_IMAXDIV // [
static static
#else // STATIC_IMAXDIV ][ #else // STATIC_IMAXDIV ][
_inline _inline
#endif // STATIC_IMAXDIV ] #endif // STATIC_IMAXDIV ]
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) {
{ imaxdiv_t result;
imaxdiv_t result;
result.quot = numer / denom; result.quot = numer / denom;
result.rem = numer % denom; result.rem = numer % denom;
if (numer < 0 && result.rem > 0) { if (numer < 0 && result.rem > 0) {
// did division wrong; must fix up // did division wrong; must fix up
++result.quot; ++result.quot;
result.rem -= denom; result.rem -= denom;
} }
return result; return result;
} }
// 7.8.2.3 The strtoimax and strtoumax functions // 7.8.2.3 The strtoimax and strtoumax functions

View File

@ -1,37 +1,37 @@
// ISO C9x compliant stdint.h for Microsoft Visual Studio // ISO C9x compliant stdint.h for Microsoft Visual Studio
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
// //
// Copyright (c) 2006-2013 Alexander Chemeris // Copyright (c) 2006-2013 Alexander Chemeris
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met: // modification, are permitted provided that the following conditions are met:
// //
// 1. Redistributions of source code must retain the above copyright notice, // 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer. // this list of conditions and the following disclaimer.
// //
// 2. Redistributions in binary form must reproduce the above copyright // 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the // notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution. // documentation and/or other materials provided with the distribution.
// //
// 3. Neither the name of the product nor the names of its contributors may // 3. Neither the name of the product nor the names of its contributors may
// be used to endorse or promote products derived from this software // be used to endorse or promote products derived from this software
// without specific prior written permission. // without specific prior written permission.
// //
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// //
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// The above software in this distribution may have been modified by // The above software in this distribution may have been modified by
// THL A29 Limited ("Tencent Modifications"). // THL A29 Limited ("Tencent Modifications").
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. // All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
#ifndef _MSC_VER // [ #ifndef _MSC_VER // [
@ -76,10 +76,10 @@
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>. // These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
// Check out Issue 9 for the details. // Check out Issue 9 for the details.
#ifndef INTMAX_C // [ #ifndef INTMAX_C // [
# define INTMAX_C INT64_C #define INTMAX_C INT64_C
#endif // INTMAX_C ] #endif // INTMAX_C ]
#ifndef UINTMAX_C // [ #ifndef UINTMAX_C // [
# define UINTMAX_C UINT64_C #define UINTMAX_C UINT64_C
#endif // UINTMAX_C ] #endif // UINTMAX_C ]
#endif // __STDC_CONSTANT_MACROS ] #endif // __STDC_CONSTANT_MACROS ]
@ -95,18 +95,18 @@
#if defined(__cplusplus) && !defined(_M_ARM) #if defined(__cplusplus) && !defined(_M_ARM)
extern "C" { extern "C" {
#endif #endif
# include <wchar.h> #include <wchar.h>
#if defined(__cplusplus) && !defined(_M_ARM) #if defined(__cplusplus) && !defined(_M_ARM)
} }
#endif #endif
// Define _W64 macros to mark types changing their size, like intptr_t. // Define _W64 macros to mark types changing their size, like intptr_t.
#ifndef _W64 #ifndef _W64
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 #if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
# define _W64 __w64 #define _W64 __w64
# else #else
# define _W64 #define _W64
# endif #endif
#endif #endif
@ -118,56 +118,56 @@ extern "C" {
// realize that, e.g. char has the same size as __int8 // realize that, e.g. char has the same size as __int8
// so we give up on __intX for them. // so we give up on __intX for them.
#if (_MSC_VER < 1300) #if (_MSC_VER < 1300)
typedef signed char int8_t; typedef signed char int8_t;
typedef signed short int16_t; typedef signed short int16_t;
typedef signed int int32_t; typedef signed int int32_t;
typedef unsigned char uint8_t; typedef unsigned char uint8_t;
typedef unsigned short uint16_t; typedef unsigned short uint16_t;
typedef unsigned int uint32_t; typedef unsigned int uint32_t;
#else #else
typedef signed __int8 int8_t; typedef signed __int8 int8_t;
typedef signed __int16 int16_t; typedef signed __int16 int16_t;
typedef signed __int32 int32_t; typedef signed __int32 int32_t;
typedef unsigned __int8 uint8_t; typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t; typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t; typedef unsigned __int32 uint32_t;
#endif #endif
typedef signed __int64 int64_t; typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t; typedef unsigned __int64 uint64_t;
// 7.18.1.2 Minimum-width integer types // 7.18.1.2 Minimum-width integer types
typedef int8_t int_least8_t; typedef int8_t int_least8_t;
typedef int16_t int_least16_t; typedef int16_t int_least16_t;
typedef int32_t int_least32_t; typedef int32_t int_least32_t;
typedef int64_t int_least64_t; typedef int64_t int_least64_t;
typedef uint8_t uint_least8_t; typedef uint8_t uint_least8_t;
typedef uint16_t uint_least16_t; typedef uint16_t uint_least16_t;
typedef uint32_t uint_least32_t; typedef uint32_t uint_least32_t;
typedef uint64_t uint_least64_t; typedef uint64_t uint_least64_t;
// 7.18.1.3 Fastest minimum-width integer types // 7.18.1.3 Fastest minimum-width integer types
typedef int8_t int_fast8_t; typedef int8_t int_fast8_t;
typedef int16_t int_fast16_t; typedef int16_t int_fast16_t;
typedef int32_t int_fast32_t; typedef int32_t int_fast32_t;
typedef int64_t int_fast64_t; typedef int64_t int_fast64_t;
typedef uint8_t uint_fast8_t; typedef uint8_t uint_fast8_t;
typedef uint16_t uint_fast16_t; typedef uint16_t uint_fast16_t;
typedef uint32_t uint_fast32_t; typedef uint32_t uint_fast32_t;
typedef uint64_t uint_fast64_t; typedef uint64_t uint_fast64_t;
// 7.18.1.4 Integer types capable of holding object pointers // 7.18.1.4 Integer types capable of holding object pointers
#ifdef _WIN64 // [ #ifdef _WIN64 // [
typedef signed __int64 intptr_t; typedef signed __int64 intptr_t;
typedef unsigned __int64 uintptr_t; typedef unsigned __int64 uintptr_t;
#else // _WIN64 ][ #else // _WIN64 ][
typedef _W64 signed int intptr_t; typedef _W64 signed int intptr_t;
typedef _W64 unsigned int uintptr_t; typedef _W64 unsigned int uintptr_t;
#endif // _WIN64 ] #endif // _WIN64 ]
// 7.18.1.5 Greatest-width integer types // 7.18.1.5 Greatest-width integer types
typedef int64_t intmax_t; typedef int64_t intmax_t;
typedef uint64_t uintmax_t; typedef uint64_t uintmax_t;
// 7.18.2 Limits of specified-width integer types // 7.18.2 Limits of specified-width integer types
@ -175,32 +175,32 @@ typedef uint64_t uintmax_t;
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
// 7.18.2.1 Limits of exact-width integer types // 7.18.2.1 Limits of exact-width integer types
#define INT8_MIN ((int8_t)_I8_MIN) #define INT8_MIN ((int8_t)_I8_MIN)
#define INT8_MAX _I8_MAX #define INT8_MAX _I8_MAX
#define INT16_MIN ((int16_t)_I16_MIN) #define INT16_MIN ((int16_t)_I16_MIN)
#define INT16_MAX _I16_MAX #define INT16_MAX _I16_MAX
#define INT32_MIN ((int32_t)_I32_MIN) #define INT32_MIN ((int32_t)_I32_MIN)
#define INT32_MAX _I32_MAX #define INT32_MAX _I32_MAX
#define INT64_MIN ((int64_t)_I64_MIN) #define INT64_MIN ((int64_t)_I64_MIN)
#define INT64_MAX _I64_MAX #define INT64_MAX _I64_MAX
#define UINT8_MAX _UI8_MAX #define UINT8_MAX _UI8_MAX
#define UINT16_MAX _UI16_MAX #define UINT16_MAX _UI16_MAX
#define UINT32_MAX _UI32_MAX #define UINT32_MAX _UI32_MAX
#define UINT64_MAX _UI64_MAX #define UINT64_MAX _UI64_MAX
// 7.18.2.2 Limits of minimum-width integer types // 7.18.2.2 Limits of minimum-width integer types
#define INT_LEAST8_MIN INT8_MIN #define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST8_MAX INT8_MAX #define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MIN INT16_MIN #define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST16_MAX INT16_MAX #define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MIN INT32_MIN #define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST32_MAX INT32_MAX #define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MIN INT64_MIN #define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST64_MAX INT64_MAX #define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX #define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX #define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX #define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX #define UINT_LEAST64_MAX UINT64_MAX
// 7.18.2.3 Limits of fastest minimum-width integer types // 7.18.2.3 Limits of fastest minimum-width integer types
#define INT_FAST8_MIN INT8_MIN #define INT_FAST8_MIN INT8_MIN
@ -218,51 +218,51 @@ typedef uint64_t uintmax_t;
// 7.18.2.4 Limits of integer types capable of holding object pointers // 7.18.2.4 Limits of integer types capable of holding object pointers
#ifdef _WIN64 // [ #ifdef _WIN64 // [
# define INTPTR_MIN INT64_MIN #define INTPTR_MIN INT64_MIN
# define INTPTR_MAX INT64_MAX #define INTPTR_MAX INT64_MAX
# define UINTPTR_MAX UINT64_MAX #define UINTPTR_MAX UINT64_MAX
#else // _WIN64 ][ #else // _WIN64 ][
# define INTPTR_MIN INT32_MIN #define INTPTR_MIN INT32_MIN
# define INTPTR_MAX INT32_MAX #define INTPTR_MAX INT32_MAX
# define UINTPTR_MAX UINT32_MAX #define UINTPTR_MAX UINT32_MAX
#endif // _WIN64 ] #endif // _WIN64 ]
// 7.18.2.5 Limits of greatest-width integer types // 7.18.2.5 Limits of greatest-width integer types
#define INTMAX_MIN INT64_MIN #define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX #define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX #define UINTMAX_MAX UINT64_MAX
// 7.18.3 Limits of other integer types // 7.18.3 Limits of other integer types
#ifdef _WIN64 // [ #ifdef _WIN64 // [
# define PTRDIFF_MIN _I64_MIN #define PTRDIFF_MIN _I64_MIN
# define PTRDIFF_MAX _I64_MAX #define PTRDIFF_MAX _I64_MAX
#else // _WIN64 ][ #else // _WIN64 ][
# define PTRDIFF_MIN _I32_MIN #define PTRDIFF_MIN _I32_MIN
# define PTRDIFF_MAX _I32_MAX #define PTRDIFF_MAX _I32_MAX
#endif // _WIN64 ] #endif // _WIN64 ]
#define SIG_ATOMIC_MIN INT_MIN #define SIG_ATOMIC_MIN INT_MIN
#define SIG_ATOMIC_MAX INT_MAX #define SIG_ATOMIC_MAX INT_MAX
#ifndef SIZE_MAX // [ #ifndef SIZE_MAX // [
# ifdef _WIN64 // [ #ifdef _WIN64 // [
# define SIZE_MAX _UI64_MAX #define SIZE_MAX _UI64_MAX
# else // _WIN64 ][ #else // _WIN64 ][
# define SIZE_MAX _UI32_MAX #define SIZE_MAX _UI32_MAX
# endif // _WIN64 ] #endif // _WIN64 ]
#endif // SIZE_MAX ] #endif // SIZE_MAX ]
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h> // WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
#ifndef WCHAR_MIN // [ #ifndef WCHAR_MIN // [
# define WCHAR_MIN 0 #define WCHAR_MIN 0
#endif // WCHAR_MIN ] #endif // WCHAR_MIN ]
#ifndef WCHAR_MAX // [ #ifndef WCHAR_MAX // [
# define WCHAR_MAX _UI16_MAX #define WCHAR_MAX _UI16_MAX
#endif // WCHAR_MAX ] #endif // WCHAR_MAX ]
#define WINT_MIN 0 #define WINT_MIN 0
#define WINT_MAX _UI16_MAX #define WINT_MAX _UI16_MAX
#endif // __STDC_LIMIT_MACROS ] #endif // __STDC_LIMIT_MACROS ]
@ -287,10 +287,10 @@ typedef uint64_t uintmax_t;
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>. // These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
// Check out Issue 9 for the details. // Check out Issue 9 for the details.
#ifndef INTMAX_C // [ #ifndef INTMAX_C // [
# define INTMAX_C INT64_C #define INTMAX_C INT64_C
#endif // INTMAX_C ] #endif // INTMAX_C ]
#ifndef UINTMAX_C // [ #ifndef UINTMAX_C // [
# define UINTMAX_C UINT64_C #define UINTMAX_C UINT64_C
#endif // UINTMAX_C ] #endif // UINTMAX_C ]
#endif // __STDC_CONSTANT_MACROS ] #endif // __STDC_CONSTANT_MACROS ]

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_OSTREAMWRAPPER_H_ #ifndef RAPIDJSON_OSTREAMWRAPPER_H_
@ -40,7 +40,7 @@ RAPIDJSON_NAMESPACE_BEGIN
\tparam StreamType Class derived from \c std::basic_ostream. \tparam StreamType Class derived from \c std::basic_ostream.
*/ */
template <typename StreamType> template <typename StreamType>
class BasicOStreamWrapper { class BasicOStreamWrapper {
public: public:
@ -56,11 +56,26 @@ public:
} }
// Not implemented // Not implemented
char Peek() const { RAPIDJSON_ASSERT(false); return 0; } char Peek() const {
char Take() { RAPIDJSON_ASSERT(false); return 0; } RAPIDJSON_ASSERT(false);
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } return 0;
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } }
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } char Take() {
RAPIDJSON_ASSERT(false);
return 0;
}
size_t Tell() const {
RAPIDJSON_ASSERT(false);
return 0;
}
char* PutBegin() {
RAPIDJSON_ASSERT(false);
return 0;
}
size_t PutEnd(char*) {
RAPIDJSON_ASSERT(false);
return 0;
}
private: private:
BasicOStreamWrapper(const BasicOStreamWrapper&); BasicOStreamWrapper(const BasicOStreamWrapper&);

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_POINTER_H_ #ifndef RAPIDJSON_POINTER_H_
@ -20,7 +20,7 @@
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(switch - enum)
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
@ -28,19 +28,19 @@ RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
//! Error code of parsing. //! Error code of parsing.
/*! \ingroup RAPIDJSON_ERRORS /*! \ingroup RAPIDJSON_ERRORS
\see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
*/ */
enum PointerParseErrorCode { enum PointerParseErrorCode {
kPointerParseErrorNone = 0, //!< The parse is successful kPointerParseErrorNone = 0, //!< The parse is successful
kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/'
kPointerParseErrorInvalidEscape, //!< Invalid escape kPointerParseErrorInvalidEscape, //!< Invalid escape
kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment
kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment
}; };
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -78,8 +78,8 @@ enum PointerParseErrorCode {
template <typename ValueType, typename Allocator = CrtAllocator> template <typename ValueType, typename Allocator = CrtAllocator>
class GenericPointer { class GenericPointer {
public: public:
typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value
typedef typename ValueType::Ch Ch; //!< Character type from Value typedef typename ValueType::Ch Ch; //!< Character type from Value
//! A token is the basic units of internal representation. //! A token is the basic units of internal representation.
/*! /*!
@ -95,9 +95,9 @@ public:
allocation, using a special constructor. allocation, using a special constructor.
*/ */
struct Token { struct Token {
const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character. const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character.
SizeType length; //!< Length of the name. SizeType length; //!< Length of the name.
SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex. SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex.
}; };
//!@name Constructors and destructor. //!@name Constructors and destructor.
@ -174,7 +174,7 @@ public:
//! Destructor. //! Destructor.
~GenericPointer() { ~GenericPointer() {
if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.
Allocator::Free(tokens_); Allocator::Free(tokens_);
RAPIDJSON_DELETE(ownAllocator_); RAPIDJSON_DELETE(ownAllocator_);
} }
@ -244,7 +244,7 @@ public:
GenericPointer Append(const Token& token, Allocator* allocator = 0) const { GenericPointer Append(const Token& token, Allocator* allocator = 0) const {
GenericPointer r; GenericPointer r;
r.allocator_ = allocator; r.allocator_ = allocator;
Ch *p = r.CopyFromRaw(*this, 1, token.length + 1); Ch* p = r.CopyFromRaw(*this, 1, token.length + 1);
std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch)); std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch));
r.tokens_[tokenCount_].name = p; r.tokens_[tokenCount_].name = p;
r.tokens_[tokenCount_].length = token.length; r.tokens_[tokenCount_].length = token.length;
@ -271,7 +271,7 @@ public:
\return A new Pointer with appended token. \return A new Pointer with appended token.
*/ */
template <typename T> template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer)) RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch>>), (GenericPointer))
Append(T* name, Allocator* allocator = 0) const { Append(T* name, Allocator* allocator = 0) const {
return Append(name, internal::StrLen(name), allocator); return Append(name, internal::StrLen(name), allocator);
} }
@ -370,9 +370,8 @@ public:
for (size_t i = 0; i < tokenCount_; i++) { for (size_t i = 0; i < tokenCount_; i++) {
if (tokens_[i].index != rhs.tokens_[i].index || if (tokens_[i].index != rhs.tokens_[i].index ||
tokens_[i].length != rhs.tokens_[i].length || tokens_[i].length != rhs.tokens_[i].length ||
(tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0)) (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length) != 0)) {
{
return false; return false;
} }
} }
@ -423,7 +422,7 @@ public:
\tparam OutputStream Type of output stream. \tparam OutputStream Type of output stream.
\param os The output stream. \param os The output stream.
*/ */
template<typename OutputStream> template <typename OutputStream>
bool Stringify(OutputStream& os) const { bool Stringify(OutputStream& os) const {
return Stringify<false, OutputStream>(os); return Stringify<false, OutputStream>(os);
} }
@ -433,7 +432,7 @@ public:
\tparam OutputStream Type of output stream. \tparam OutputStream Type of output stream.
\param os The output stream. \param os The output stream.
*/ */
template<typename OutputStream> template <typename OutputStream>
bool StringifyUriFragment(OutputStream& os) const { bool StringifyUriFragment(OutputStream& os) const {
return Stringify<true, OutputStream>(os); return Stringify<true, OutputStream>(os);
} }
@ -462,7 +461,7 @@ public:
RAPIDJSON_ASSERT(IsValid()); RAPIDJSON_ASSERT(IsValid());
ValueType* v = &root; ValueType* v = &root;
bool exist = true; bool exist = true;
for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { for (const Token* t = tokens_; t != tokens_ + tokenCount_; ++t) {
if (v->IsArray() && t->name[0] == '-' && t->length == 1) { if (v->IsArray() && t->name[0] == '-' && t->length == 1) {
v->PushBack(ValueType().Move(), allocator); v->PushBack(ValueType().Move(), allocator);
v = &((*v)[v->Size() - 1]); v = &((*v)[v->Size() - 1]);
@ -540,15 +539,14 @@ public:
ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const { ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const {
RAPIDJSON_ASSERT(IsValid()); RAPIDJSON_ASSERT(IsValid());
ValueType* v = &root; ValueType* v = &root;
for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { for (const Token* t = tokens_; t != tokens_ + tokenCount_; ++t) {
switch (v->GetType()) { switch (v->GetType()) {
case kObjectType: case kObjectType: {
{ typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length))); if (m == v->MemberEnd())
if (m == v->MemberEnd()) break;
break; v = &m->value;
v = &m->value; }
}
continue; continue;
case kArrayType: case kArrayType:
if (t->index == kPointerInvalidIndex || t->index >= v->Size()) if (t->index == kPointerInvalidIndex || t->index >= v->Size())
@ -572,7 +570,7 @@ public:
\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
\return Pointer to the value if it can be resolved. Otherwise null. \return Pointer to the value if it can be resolved. Otherwise null.
*/ */
const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const { const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const {
return Get(const_cast<ValueType&>(root), unresolvedTokenIndex); return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);
} }
@ -618,7 +616,7 @@ public:
\tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
*/ */
template <typename T> template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T>>), (ValueType&))
GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const { GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const {
return GetWithDefault(root, ValueType(defaultValue).Move(), allocator); return GetWithDefault(root, ValueType(defaultValue).Move(), allocator);
} }
@ -634,7 +632,7 @@ public:
ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const { ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const {
return GetWithDefault(document, defaultValue, document.GetAllocator()); return GetWithDefault(document, defaultValue, document.GetAllocator());
} }
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
//! Query a value in a document with default std::basic_string. //! Query a value in a document with default std::basic_string.
template <typename stackAllocator> template <typename stackAllocator>
@ -648,7 +646,7 @@ public:
\tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
*/ */
template <typename T, typename stackAllocator> template <typename T, typename stackAllocator>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T>>), (ValueType&))
GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T defaultValue) const { GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T defaultValue) const {
return GetWithDefault(document, defaultValue, document.GetAllocator()); return GetWithDefault(document, defaultValue, document.GetAllocator());
} }
@ -694,7 +692,7 @@ public:
\tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
*/ */
template <typename T> template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T>>), (ValueType&))
Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const { Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const {
return Create(root, allocator) = ValueType(value).Move(); return Create(root, allocator) = ValueType(value).Move();
} }
@ -730,9 +728,9 @@ public:
\tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
*/ */
template <typename T, typename stackAllocator> template <typename T, typename stackAllocator>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T>>), (ValueType&))
Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T value) const { Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T value) const {
return Create(document) = value; return Create(document) = value;
} }
//@} //@}
@ -776,16 +774,14 @@ public:
ValueType* v = &root; ValueType* v = &root;
const Token* last = tokens_ + (tokenCount_ - 1); const Token* last = tokens_ + (tokenCount_ - 1);
for (const Token *t = tokens_; t != last; ++t) { for (const Token* t = tokens_; t != last; ++t) {
switch (v->GetType()) { switch (v->GetType()) {
case kObjectType: case kObjectType: {
{ typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length)));
typename ValueType::MemberIterator m = v->FindMember(GenericValue<EncodingType>(GenericStringRef<Ch>(t->name, t->length))); if (m == v->MemberEnd())
if (m == v->MemberEnd()) return false;
return false; v = &m->value;
v = &m->value; } break;
}
break;
case kArrayType: case kArrayType:
if (t->index == kPointerInvalidIndex || t->index >= v->Size()) if (t->index == kPointerInvalidIndex || t->index >= v->Size())
return false; return false;
@ -822,12 +818,12 @@ private:
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens
for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) for (Token* t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)
nameBufferSize += t->length; nameBufferSize += t->length;
tokenCount_ = rhs.tokenCount_ + extraToken; tokenCount_ = rhs.tokenCount_ + extraToken;
tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); tokens_ = static_cast<Token*>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));
nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_); nameBuffer_ = reinterpret_cast<Ch*>(tokens_ + tokenCount_);
if (rhs.tokenCount_ > 0) { if (rhs.tokenCount_ > 0) {
std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));
} }
@ -837,7 +833,7 @@ private:
// Adjust pointers to name buffer // Adjust pointers to name buffer
std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) for (Token* t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)
t->name += diff; t->name += diff;
return nameBuffer_ + nameBufferSize; return nameBuffer_ + nameBufferSize;
@ -849,7 +845,7 @@ private:
\param c The character (code unit) to be tested. \param c The character (code unit) to be tested.
*/ */
bool NeedPercentEncode(Ch c) const { bool NeedPercentEncode(Ch c) const {
return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~'); return !((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c == '~');
} }
//! Parse a JSON String or its URI fragment representation into tokens. //! Parse a JSON String or its URI fragment representation into tokens.
@ -871,12 +867,12 @@ private:
// Count number of '/' as tokenCount // Count number of '/' as tokenCount
tokenCount_ = 0; tokenCount_ = 0;
for (const Ch* s = source; s != source + length; s++) for (const Ch* s = source; s != source + length; s++)
if (*s == '/') if (*s == '/')
tokenCount_++; tokenCount_++;
Token* token = tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch))); Token* token = tokens_ = static_cast<Token*>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch)));
Ch* name = nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_); Ch* name = nameBuffer_ = reinterpret_cast<Ch*>(tokens_ + tokenCount_);
size_t i = 0; size_t i = 0;
// Detect if it is a URI fragment // Detect if it is a URI fragment
@ -928,13 +924,15 @@ private:
} }
i++; i++;
// Escaping "~0" -> '~', "~1" -> '/' // Escaping "~0" -> '~', "~1" -> '/'
if (c == '~') { if (c == '~') {
if (i < length) { if (i < length) {
c = source[i]; c = source[i];
if (c == '0') c = '~'; if (c == '0')
else if (c == '1') c = '/'; c = '~';
else if (c == '1')
c = '/';
else { else {
parseErrorCode_ = kPointerParseErrorInvalidEscape; parseErrorCode_ = kPointerParseErrorInvalidEscape;
goto error; goto error;
@ -967,7 +965,7 @@ private:
if (isNumber) { if (isNumber) {
for (size_t j = 0; j < token->length; j++) { for (size_t j = 0; j < token->length; j++) {
SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0'); SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0');
if (m < n) { // overflow detection if (m < n) { // overflow detection
isNumber = false; isNumber = false;
break; break;
} }
@ -998,14 +996,14 @@ private:
\tparam OutputStream type of output stream. \tparam OutputStream type of output stream.
\param os The output stream. \param os The output stream.
*/ */
template<bool uriFragment, typename OutputStream> template <bool uriFragment, typename OutputStream>
bool Stringify(OutputStream& os) const { bool Stringify(OutputStream& os) const {
RAPIDJSON_ASSERT(IsValid()); RAPIDJSON_ASSERT(IsValid());
if (uriFragment) if (uriFragment)
os.Put('#'); os.Put('#');
for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { for (Token* t = tokens_; t != tokens_ + tokenCount_; ++t) {
os.Put('/'); os.Put('/');
for (size_t j = 0; j < t->length; j++) { for (size_t j = 0; j < t->length; j++) {
Ch c = t->name[j]; Ch c = t->name[j];
@ -1017,11 +1015,11 @@ private:
os.Put('~'); os.Put('~');
os.Put('1'); os.Put('1');
} }
else if (uriFragment && NeedPercentEncode(c)) { else if (uriFragment && NeedPercentEncode(c)) {
// Transcode to UTF8 sequence // Transcode to UTF8 sequence
GenericStringStream<typename ValueType::EncodingType> source(&t->name[j]); GenericStringStream<typename ValueType::EncodingType> source(&t->name[j]);
PercentEncodeStream<OutputStream> target(os); PercentEncodeStream<OutputStream> target(os);
if (!Transcoder<EncodingType, UTF8<> >().Validate(source, target)) if (!Transcoder<EncodingType, UTF8<>>().Validate(source, target))
return false; return false;
j += source.Tell() - 1; j += source.Tell() - 1;
} }
@ -1059,9 +1057,12 @@ private:
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
c = static_cast<Ch>(c << 4); c = static_cast<Ch>(c << 4);
Ch h = *src_; Ch h = *src_;
if (h >= '0' && h <= '9') c = static_cast<Ch>(c + h - '0'); if (h >= '0' && h <= '9')
else if (h >= 'A' && h <= 'F') c = static_cast<Ch>(c + h - 'A' + 10); c = static_cast<Ch>(c + h - '0');
else if (h >= 'a' && h <= 'f') c = static_cast<Ch>(c + h - 'a' + 10); else if (h >= 'A' && h <= 'F')
c = static_cast<Ch>(c + h - 'A' + 10);
else if (h >= 'a' && h <= 'f')
c = static_cast<Ch>(c + h - 'a' + 10);
else { else {
valid_ = false; valid_ = false;
return 0; return 0;
@ -1075,10 +1076,10 @@ private:
bool IsValid() const { return valid_; } bool IsValid() const { return valid_; }
private: private:
const Ch* src_; //!< Current read position. const Ch* src_; //!< Current read position.
const Ch* head_; //!< Original head of the string. const Ch* head_; //!< Original head of the string.
const Ch* end_; //!< Past-the-end position. const Ch* end_; //!< Past-the-end position.
bool valid_; //!< Whether the parsing is valid. bool valid_; //!< Whether the parsing is valid.
}; };
//! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence. //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence.
@ -1093,17 +1094,18 @@ private:
os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u >> 4])); os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u >> 4]));
os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u & 15])); os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u & 15]));
} }
private: private:
OutputStream& os_; OutputStream& os_;
}; };
Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_.
Allocator* ownAllocator_; //!< Allocator owned by this Pointer. Allocator* ownAllocator_; //!< Allocator owned by this Pointer.
Ch* nameBuffer_; //!< A buffer containing all names in tokens. Ch* nameBuffer_; //!< A buffer containing all names in tokens.
Token* tokens_; //!< A list of tokens. Token* tokens_; //!< A list of tokens.
size_t tokenCount_; //!< Number of tokens in tokens_. size_t tokenCount_; //!< Number of tokens in tokens_.
size_t parseErrorOffset_; //!< Offset in code unit when parsing fail. size_t parseErrorOffset_; //!< Offset in code unit when parsing fail.
PointerParseErrorCode parseErrorCode_; //!< Parsing error code. PointerParseErrorCode parseErrorCode_; //!< Parsing error code.
}; };
//! GenericPointer for Value (UTF-8, default allocator). //! GenericPointer for Value (UTF-8, default allocator).
@ -1120,7 +1122,7 @@ typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer<typena
} }
template <typename T, typename CharType, size_t N> template <typename T, typename CharType, size_t N>
typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) { typename T::ValueType& CreateValueByPointer(T& root, const CharType (&source)[N], typename T::AllocatorType& a) {
return GenericPointer<typename T::ValueType>(source, N - 1).Create(root, a); return GenericPointer<typename T::ValueType>(source, N - 1).Create(root, a);
} }
@ -1132,7 +1134,7 @@ typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, c
} }
template <typename DocumentType, typename CharType, size_t N> template <typename DocumentType, typename CharType, size_t N>
typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) { typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType (&source)[N]) {
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document); return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document);
} }
@ -1154,7 +1156,7 @@ typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], s
} }
template <typename T, typename CharType, size_t N> template <typename T, typename CharType, size_t N>
const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) { const typename T::ValueType* GetValueByPointer(const T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) {
return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex); return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
} }
@ -1178,31 +1180,31 @@ typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointe
#endif #endif
template <typename T, typename T2> template <typename T, typename T2>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&)) RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2>>), (typename T::ValueType&))
GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) { GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) {
return pointer.GetWithDefault(root, defaultValue, a); return pointer.GetWithDefault(root, defaultValue, a);
} }
template <typename T, typename CharType, size_t N> template <typename T, typename CharType, size_t N>
typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType (&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {
return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a); return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
} }
template <typename T, typename CharType, size_t N> template <typename T, typename CharType, size_t N>
typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) { typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType (&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) {
return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a); return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
} }
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
template <typename T, typename CharType, size_t N> template <typename T, typename CharType, size_t N>
typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) { typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType (&source)[N], const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a); return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
} }
#endif #endif
template <typename T, typename CharType, size_t N, typename T2> template <typename T, typename CharType, size_t N, typename T2>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&)) RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2>>), (typename T::ValueType&))
GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) { GetValueByPointerWithDefault(T& root, const CharType (&source)[N], T2 defaultValue, typename T::AllocatorType& a) {
return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a); return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
} }
@ -1226,31 +1228,31 @@ typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& doc
#endif #endif
template <typename DocumentType, typename T2> template <typename DocumentType, typename T2>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&)) RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2>>), (typename DocumentType::ValueType&))
GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) { GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) {
return pointer.GetWithDefault(document, defaultValue); return pointer.GetWithDefault(document, defaultValue);
} }
template <typename DocumentType, typename CharType, size_t N> template <typename DocumentType, typename CharType, size_t N>
typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) { typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType (&source)[N], const typename DocumentType::ValueType& defaultValue) {
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue); return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
} }
template <typename DocumentType, typename CharType, size_t N> template <typename DocumentType, typename CharType, size_t N>
typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) { typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType (&source)[N], const typename DocumentType::Ch* defaultValue) {
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue); return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
} }
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
template <typename DocumentType, typename CharType, size_t N> template <typename DocumentType, typename CharType, size_t N>
typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& defaultValue) { typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType (&source)[N], const std::basic_string<typename DocumentType::Ch>& defaultValue) {
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue); return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
} }
#endif #endif
template <typename DocumentType, typename CharType, size_t N, typename T2> template <typename DocumentType, typename CharType, size_t N, typename T2>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&)) RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2>>), (typename DocumentType::ValueType&))
GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) { GetValueByPointerWithDefault(DocumentType& document, const CharType (&source)[N], T2 defaultValue) {
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue); return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
} }
@ -1279,36 +1281,36 @@ typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename
#endif #endif
template <typename T, typename T2> template <typename T, typename T2>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&)) RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2>>), (typename T::ValueType&))
SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) { SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) {
return pointer.Set(root, value, a); return pointer.Set(root, value, a);
} }
template <typename T, typename CharType, size_t N> template <typename T, typename CharType, size_t N>
typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { typename T::ValueType& SetValueByPointer(T& root, const CharType (&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a); return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
} }
template <typename T, typename CharType, size_t N> template <typename T, typename CharType, size_t N>
typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) { typename T::ValueType& SetValueByPointer(T& root, const CharType (&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) {
return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a); return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
} }
template <typename T, typename CharType, size_t N> template <typename T, typename CharType, size_t N>
typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) { typename T::ValueType& SetValueByPointer(T& root, const CharType (&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) {
return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a); return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
} }
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
template <typename T, typename CharType, size_t N> template <typename T, typename CharType, size_t N>
typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) { typename T::ValueType& SetValueByPointer(T& root, const CharType (&source)[N], const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a); return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
} }
#endif #endif
template <typename T, typename CharType, size_t N, typename T2> template <typename T, typename CharType, size_t N, typename T2>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&)) RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2>>), (typename T::ValueType&))
SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) { SetValueByPointer(T& root, const CharType (&source)[N], T2 value, typename T::AllocatorType& a) {
return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a); return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
} }
@ -1337,36 +1339,36 @@ typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, cons
#endif #endif
template <typename DocumentType, typename T2> template <typename DocumentType, typename T2>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&)) RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2>>), (typename DocumentType::ValueType&))
SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) { SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) {
return pointer.Set(document, value); return pointer.Set(document, value);
} }
template <typename DocumentType, typename CharType, size_t N> template <typename DocumentType, typename CharType, size_t N>
typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType (&source)[N], typename DocumentType::ValueType& value) {
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value); return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
} }
template <typename DocumentType, typename CharType, size_t N> template <typename DocumentType, typename CharType, size_t N>
typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) { typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType (&source)[N], const typename DocumentType::ValueType& value) {
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value); return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
} }
template <typename DocumentType, typename CharType, size_t N> template <typename DocumentType, typename CharType, size_t N>
typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) { typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType (&source)[N], const typename DocumentType::Ch* value) {
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value); return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
} }
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
template <typename DocumentType, typename CharType, size_t N> template <typename DocumentType, typename CharType, size_t N>
typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& value) { typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType (&source)[N], const std::basic_string<typename DocumentType::Ch>& value) {
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value); return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
} }
#endif #endif
template <typename DocumentType, typename CharType, size_t N, typename T2> template <typename DocumentType, typename CharType, size_t N, typename T2>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&)) RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2>>), (typename DocumentType::ValueType&))
SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) { SetValueByPointer(DocumentType& document, const CharType (&source)[N], T2 value) {
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value); return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
} }
@ -1378,7 +1380,7 @@ typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer<typename
} }
template <typename T, typename CharType, size_t N> template <typename T, typename CharType, size_t N>
typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { typename T::ValueType& SwapValueByPointer(T& root, const CharType (&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
return GenericPointer<typename T::ValueType>(source, N - 1).Swap(root, value, a); return GenericPointer<typename T::ValueType>(source, N - 1).Swap(root, value, a);
} }
@ -1388,7 +1390,7 @@ typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, con
} }
template <typename DocumentType, typename CharType, size_t N> template <typename DocumentType, typename CharType, size_t N>
typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType (&source)[N], typename DocumentType::ValueType& value) {
return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value); return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value);
} }
@ -1400,7 +1402,7 @@ bool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& p
} }
template <typename T, typename CharType, size_t N> template <typename T, typename CharType, size_t N>
bool EraseValueByPointer(T& root, const CharType(&source)[N]) { bool EraseValueByPointer(T& root, const CharType (&source)[N]) {
return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root); return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root);
} }

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_PRETTYWRITER_H_ #ifndef RAPIDJSON_PRETTYWRITER_H_
@ -24,7 +24,7 @@ RAPIDJSON_DIAG_OFF(effc++)
#if defined(__clang__) #if defined(__clang__)
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(c++98-compat) RAPIDJSON_DIAG_OFF(c++ 98 - compat)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -33,8 +33,8 @@ RAPIDJSON_NAMESPACE_BEGIN
/*! \see PrettyWriter::SetFormatOptions /*! \see PrettyWriter::SetFormatOptions
*/ */
enum PrettyFormatOptions { enum PrettyFormatOptions {
kFormatDefault = 0, //!< Default pretty formatting. kFormatDefault = 0, //!< Default pretty formatting.
kFormatSingleLineArray = 1 //!< Format arrays on a single line. kFormatSingleLineArray = 1 //!< Format arrays on a single line.
}; };
//! Writer with indentation and spacing. //! Writer with indentation and spacing.
@ -44,7 +44,7 @@ enum PrettyFormatOptions {
\tparam TargetEncoding Encoding of output stream. \tparam TargetEncoding Encoding of output stream.
\tparam StackAllocator Type of allocator for allocating memory of stack. \tparam StackAllocator Type of allocator for allocating memory of stack.
*/ */
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> template <typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> { class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
public: public:
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> Base; typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> Base;
@ -55,16 +55,13 @@ public:
\param allocator User supplied allocator. If it is null, it will create a private one. \param allocator User supplied allocator. If it is null, it will create a private one.
\param levelDepth Initial capacity of stack. \param levelDepth Initial capacity of stack.
*/ */
explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
PrettyWriter(PrettyWriter&& rhs) : PrettyWriter(PrettyWriter&& rhs) : Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {}
Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {}
#endif #endif
//! Set custom indentation. //! Set custom indentation.
@ -92,13 +89,34 @@ public:
*/ */
//@{ //@{
bool Null() { PrettyPrefix(kNullType); return Base::EndValue(Base::WriteNull()); } bool Null() {
bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::EndValue(Base::WriteBool(b)); } PrettyPrefix(kNullType);
bool Int(int i) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt(i)); } return Base::EndValue(Base::WriteNull());
bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint(u)); } }
bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt64(i64)); } bool Bool(bool b) {
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint64(u64)); } PrettyPrefix(b ? kTrueType : kFalseType);
bool Double(double d) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteDouble(d)); } return Base::EndValue(Base::WriteBool(b));
}
bool Int(int i) {
PrettyPrefix(kNumberType);
return Base::EndValue(Base::WriteInt(i));
}
bool Uint(unsigned u) {
PrettyPrefix(kNumberType);
return Base::EndValue(Base::WriteUint(u));
}
bool Int64(int64_t i64) {
PrettyPrefix(kNumberType);
return Base::EndValue(Base::WriteInt64(i64));
}
bool Uint64(uint64_t u64) {
PrettyPrefix(kNumberType);
return Base::EndValue(Base::WriteUint64(u64));
}
bool Double(double d) {
PrettyPrefix(kNumberType);
return Base::EndValue(Base::WriteDouble(d));
}
bool RawNumber(const Ch* str, SizeType length, bool copy = false) { bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
RAPIDJSON_ASSERT(str != 0); RAPIDJSON_ASSERT(str != 0);
@ -133,13 +151,13 @@ public:
return Key(str.data(), SizeType(str.size())); return Key(str.data(), SizeType(str.size()));
} }
#endif #endif
bool EndObject(SizeType memberCount = 0) { bool EndObject(SizeType memberCount = 0) {
(void)memberCount; (void)memberCount;
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); // currently inside an Array, not Object RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); // currently inside an Array, not Object
RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top<typename Base::Level>()->valueCount % 2); // Object has a Key without a Value RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top<typename Base::Level>()->valueCount % 2); // Object has a Key without a Value
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0; bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
if (!empty) { if (!empty) {
@ -222,7 +240,7 @@ protected:
WriteIndent(); WriteIndent();
} }
} }
else { // in object else { // in object
if (level->valueCount > 0) { if (level->valueCount > 0) {
if (level->valueCount % 2 == 0) { if (level->valueCount % 2 == 0) {
Base::os_->Put(','); Base::os_->Put(',');
@ -240,16 +258,16 @@ protected:
WriteIndent(); WriteIndent();
} }
if (!level->inArray && level->valueCount % 2 == 0) if (!level->inArray && level->valueCount % 2 == 0)
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
level->valueCount++; level->valueCount++;
} }
else { else {
RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
Base::hasRoot_ = true; Base::hasRoot_ = true;
} }
} }
void WriteIndent() { void WriteIndent() {
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
PutN(*Base::os_, static_cast<typename OutputStream::Ch>(indentChar_), count); PutN(*Base::os_, static_cast<typename OutputStream::Ch>(indentChar_), count);
} }

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_RAPIDJSON_H_ #ifndef RAPIDJSON_RAPIDJSON_H_
@ -36,8 +36,8 @@
different translation units of a single application. different translation units of a single application.
*/ */
#include <cstdlib> // malloc(), realloc(), free(), size_t #include <cstdlib> // malloc(), realloc(), free(), size_t
#include <cstring> // memset(), memcpy(), memmove(), memcmp() #include <cstring> // memset(), memcpy(), memmove(), memcmp()
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_VERSION_STRING // RAPIDJSON_VERSION_STRING
@ -47,12 +47,12 @@
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
// token stringification // token stringification
#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) #define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
#define RAPIDJSON_DO_STRINGIFY(x) #x #define RAPIDJSON_DO_STRINGIFY(x) #x
// token concatenation // token concatenation
#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) #define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) #define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
#define RAPIDJSON_DO_JOIN2(X, Y) X##Y #define RAPIDJSON_DO_JOIN2(X, Y) X##Y
//!@endcond //!@endcond
@ -195,7 +195,7 @@
*/ */
#ifndef RAPIDJSON_NO_INT64DEFINE #ifndef RAPIDJSON_NO_INT64DEFINE
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 #if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013
#include "msinttypes/stdint.h" #include "msinttypes/stdint.h"
#include "msinttypes/inttypes.h" #include "msinttypes/inttypes.h"
#else #else
@ -226,8 +226,8 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ENDIAN // RAPIDJSON_ENDIAN
#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine #define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine #define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
//! Endianness of the machine. //! Endianness of the machine.
/*! /*!
@ -244,41 +244,41 @@
*/ */
#ifndef RAPIDJSON_ENDIAN #ifndef RAPIDJSON_ENDIAN
// Detect with GCC 4.6's macro // Detect with GCC 4.6's macro
# ifdef __BYTE_ORDER__ #ifdef __BYTE_ORDER__
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN #define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN #define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# else #else
# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. #error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
# endif // __BYTE_ORDER__ #endif // __BYTE_ORDER__
// Detect with GLIBC's endian.h // Detect with GLIBC's endian.h
# elif defined(__GLIBC__) #elif defined(__GLIBC__)
# include <endian.h> #include <endian.h>
# if (__BYTE_ORDER == __LITTLE_ENDIAN) #if (__BYTE_ORDER == __LITTLE_ENDIAN)
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN #define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif (__BYTE_ORDER == __BIG_ENDIAN) #elif (__BYTE_ORDER == __BIG_ENDIAN)
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN #define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# else #else
# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. #error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
# endif // __GLIBC__ #endif // __GLIBC__
// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro // Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) #elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN #define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) #elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN #define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
// Detect with architecture macros // Detect with architecture macros
# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) #elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN #define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) #elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN #define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) #elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN #define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif defined(RAPIDJSON_DOXYGEN_RUNNING) #elif defined(RAPIDJSON_DOXYGEN_RUNNING)
# define RAPIDJSON_ENDIAN #define RAPIDJSON_ENDIAN
# else #else
# error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN. #error Unknown machine endianness detected. User needs to define RAPIDJSON_ENDIAN.
# endif #endif
#endif // RAPIDJSON_ENDIAN #endif // RAPIDJSON_ENDIAN
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -343,11 +343,11 @@
#if RAPIDJSON_64BIT != 1 #if RAPIDJSON_64BIT != 1
#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1 #error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1
#endif #endif
#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x)))) #define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type*>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF)))) #define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type*>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
#else #else
#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x)) #define RAPIDJSON_SETPOINTER(type, p, x) (p = (x))
#define RAPIDJSON_GETPOINTER(type, p) (p) #define RAPIDJSON_GETPOINTER(type, p) (p)
#endif #endif
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -379,8 +379,7 @@
If any of these symbols is defined, RapidJSON defines the macro If any of these symbols is defined, RapidJSON defines the macro
\c RAPIDJSON_SIMD to indicate the availability of the optimized code. \c RAPIDJSON_SIMD to indicate the availability of the optimized code.
*/ */
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING)
|| defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING)
#define RAPIDJSON_SIMD #define RAPIDJSON_SIMD
#endif #endif
@ -442,9 +441,9 @@ RAPIDJSON_NAMESPACE_END
// Prefer C++11 static_assert, if available // Prefer C++11 static_assert, if available
#ifndef RAPIDJSON_STATIC_ASSERT #ifndef RAPIDJSON_STATIC_ASSERT
#if RAPIDJSON_CPLUSPLUS >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 ) #if RAPIDJSON_CPLUSPLUS >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)
#define RAPIDJSON_STATIC_ASSERT(x) \ #define RAPIDJSON_STATIC_ASSERT(x) \
static_assert(x, RAPIDJSON_STRINGIFY(x)) static_assert(x, RAPIDJSON_STRINGIFY(x))
#endif // C++11 #endif // C++11
#endif // RAPIDJSON_STATIC_ASSERT #endif // RAPIDJSON_STATIC_ASSERT
@ -454,15 +453,20 @@ RAPIDJSON_NAMESPACE_END
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
template <bool x> struct STATIC_ASSERTION_FAILURE; template <bool x>
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; }; struct STATIC_ASSERTION_FAILURE;
template <size_t x> struct StaticAssertTest {}; template <>
struct STATIC_ASSERTION_FAILURE<true> {
enum { value = 1 };
};
template <size_t x>
struct StaticAssertTest {};
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
#else #else
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
#endif #endif
#ifndef __clang__ #ifndef __clang__
//!@endcond //!@endcond
@ -473,10 +477,10 @@ RAPIDJSON_NAMESPACE_END
\param x compile-time condition \param x compile-time condition
\hideinitializer \hideinitializer
*/ */
#define RAPIDJSON_STATIC_ASSERT(x) \ #define RAPIDJSON_STATIC_ASSERT(x) \
typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \ sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x)>)> \
RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
#endif // RAPIDJSON_STATIC_ASSERT #endif // RAPIDJSON_STATIC_ASSERT
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -513,13 +517,14 @@ RAPIDJSON_NAMESPACE_END
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#define RAPIDJSON_MULTILINEMACRO_BEGIN do { #define RAPIDJSON_MULTILINEMACRO_BEGIN do {
#define RAPIDJSON_MULTILINEMACRO_END \ #define RAPIDJSON_MULTILINEMACRO_END \
} while((void)0, 0) } \
while ((void)0, 0)
// adopted from Boost // adopted from Boost
#define RAPIDJSON_VERSION_CODE(x,y,z) \ #define RAPIDJSON_VERSION_CODE(x, y, z) \
(((x)*100000) + ((y)*100) + (z)) (((x)*100000) + ((y)*100) + (z))
#if defined(__has_builtin) #if defined(__has_builtin)
#define RAPIDJSON_HAS_BUILTIN(x) __has_builtin(x) #define RAPIDJSON_HAS_BUILTIN(x) __has_builtin(x)
@ -532,32 +537,33 @@ RAPIDJSON_NAMESPACE_END
#if defined(__GNUC__) #if defined(__GNUC__)
#define RAPIDJSON_GNUC \ #define RAPIDJSON_GNUC \
RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) RAPIDJSON_VERSION_CODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#endif #endif
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0)) #if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4, 2, 0))
#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) #define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) #define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
#define RAPIDJSON_DIAG_OFF(x) \ #define RAPIDJSON_DIAG_OFF(x) \
RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W, x)))
// push/pop support in Clang and GCC>=4.6 // push/pop support in Clang and GCC>=4.6
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) #if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4, 6, 0))
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) #define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) #define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
#else // GCC >= 4.2, < 4.6 #else // GCC >= 4.2, < 4.6
#define RAPIDJSON_DIAG_PUSH /* ignored */ #define RAPIDJSON_DIAG_PUSH /* ignored */
#define RAPIDJSON_DIAG_POP /* ignored */ #define RAPIDJSON_DIAG_POP /* ignored */
#endif #endif
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
// pragma (MSVC specific) // pragma (MSVC specific)
#define RAPIDJSON_PRAGMA(x) __pragma(x) #define RAPIDJSON_PRAGMA(x) __pragma(x)
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x)) #define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))
#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x) #define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable \
: x)
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) #define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) #define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
@ -586,9 +592,9 @@ RAPIDJSON_NAMESPACE_END
#else #else
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
#endif #endif
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4, 3, 0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
(defined(_MSC_VER) && _MSC_VER >= 1600) || \ (defined(_MSC_VER) && _MSC_VER >= 1600) || \
(defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
#else #else
@ -605,8 +611,8 @@ RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 #define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
#elif defined(__clang__) #elif defined(__clang__)
#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) #define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4, 6, 0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
(defined(_MSC_VER) && _MSC_VER >= 1900) || \ (defined(_MSC_VER) && _MSC_VER >= 1900) || \
(defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 #define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
#else #else
@ -633,9 +639,9 @@ RAPIDJSON_NAMESPACE_END
#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR #ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR
#if defined(__clang__) #if defined(__clang__)
#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) #define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4, 6, 0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
(defined(_MSC_VER) && _MSC_VER >= 1700) || \ (defined(_MSC_VER) && _MSC_VER >= 1700) || \
(defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__)) (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 #define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
#else #else
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 #define RAPIDJSON_HAS_CXX11_RANGE_FOR 0
@ -650,23 +656,23 @@ RAPIDJSON_NAMESPACE_END
#endif #endif
#if RAPIDJSON_HAS_CXX17 #if RAPIDJSON_HAS_CXX17
# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]] #define RAPIDJSON_DELIBERATE_FALLTHROUGH [[fallthrough]]
#elif defined(__has_cpp_attribute) #elif defined(__has_cpp_attribute)
# if __has_cpp_attribute(clang::fallthrough) #if __has_cpp_attribute(clang::fallthrough)
# define RAPIDJSON_DELIBERATE_FALLTHROUGH [[clang::fallthrough]] #define RAPIDJSON_DELIBERATE_FALLTHROUGH [[clang::fallthrough]]
# elif __has_cpp_attribute(fallthrough) #elif __has_cpp_attribute(fallthrough)
# define RAPIDJSON_DELIBERATE_FALLTHROUGH __attribute__((fallthrough)) #define RAPIDJSON_DELIBERATE_FALLTHROUGH __attribute__((fallthrough))
# else
# define RAPIDJSON_DELIBERATE_FALLTHROUGH
# endif
#else #else
# define RAPIDJSON_DELIBERATE_FALLTHROUGH #define RAPIDJSON_DELIBERATE_FALLTHROUGH
#endif
#else
#define RAPIDJSON_DELIBERATE_FALLTHROUGH
#endif #endif
//!@endcond //!@endcond
//! Assertion (in non-throwing contexts). //! Assertion (in non-throwing contexts).
/*! \ingroup RAPIDJSON_CONFIG /*! \ingroup RAPIDJSON_CONFIG
Some functions provide a \c noexcept guarantee, if the compiler supports it. Some functions provide a \c noexcept guarantee, if the compiler supports it.
In these cases, the \ref RAPIDJSON_ASSERT macro cannot be overridden to In these cases, the \ref RAPIDJSON_ASSERT macro cannot be overridden to
throw an exception. This macro adds a separate customization point for throw an exception. This macro adds a separate customization point for
@ -727,13 +733,13 @@ RAPIDJSON_NAMESPACE_BEGIN
//! Type of JSON value //! Type of JSON value
enum Type { enum Type {
kNullType = 0, //!< null kNullType = 0, //!< null
kFalseType = 1, //!< false kFalseType = 1, //!< false
kTrueType = 2, //!< true kTrueType = 2, //!< true
kObjectType = 3, //!< object kObjectType = 3, //!< object
kArrayType = 4, //!< array kArrayType = 4, //!< array
kStringType = 5, //!< string kStringType = 5, //!< string
kNumberType = 6 //!< number kNumberType = 6 //!< number
}; };
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View File

@ -69,7 +69,7 @@ concept Stream {
For custom stream, this type can be specialized for other configuration. For custom stream, this type can be specialized for other configuration.
See TEST(Reader, CustomStringStream) in readertest.cpp for example. See TEST(Reader, CustomStringStream) in readertest.cpp for example.
*/ */
template<typename Stream> template <typename Stream>
struct StreamTraits { struct StreamTraits {
//! Whether to make local copy of stream for optimization during parsing. //! Whether to make local copy of stream for optimization during parsing.
/*! /*!
@ -80,20 +80,20 @@ struct StreamTraits {
}; };
//! Reserve n characters for writing to a stream. //! Reserve n characters for writing to a stream.
template<typename Stream> template <typename Stream>
inline void PutReserve(Stream& stream, size_t count) { inline void PutReserve(Stream& stream, size_t count) {
(void)stream; (void)stream;
(void)count; (void)count;
} }
//! Write character to a stream, presuming buffer is reserved. //! Write character to a stream, presuming buffer is reserved.
template<typename Stream> template <typename Stream>
inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { inline void PutUnsafe(Stream& stream, typename Stream::Ch c) {
stream.Put(c); stream.Put(c);
} }
//! Put N copies of a character to a stream. //! Put N copies of a character to a stream.
template<typename Stream, typename Ch> template <typename Stream, typename Ch>
inline void PutN(Stream& stream, Ch c, size_t n) { inline void PutN(Stream& stream, Ch c, size_t n) {
PutReserve(stream, n); PutReserve(stream, n);
for (size_t i = 0; i < n; i++) for (size_t i = 0; i < n; i++)
@ -111,15 +111,15 @@ inline void PutN(Stream& stream, Ch c, size_t n) {
#if defined(_MSC_VER) && _MSC_VER <= 1800 #if defined(_MSC_VER) && _MSC_VER <= 1800
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4702) // unreachable code RAPIDJSON_DIAG_OFF(4702) // unreachable code
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif #endif
template <typename InputStream, typename Encoding = UTF8<> > template <typename InputStream, typename Encoding = UTF8<>>
class GenericStreamWrapper { class GenericStreamWrapper {
public: public:
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
GenericStreamWrapper(InputStream& is): is_(is) {} GenericStreamWrapper(InputStream& is) : is_(is) {}
Ch Peek() const { return is_.Peek(); } Ch Peek() const { return is_.Peek(); }
Ch Take() { return is_.Take(); } Ch Take() { return is_.Take(); }
@ -154,28 +154,34 @@ template <typename Encoding>
struct GenericStringStream { struct GenericStringStream {
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
GenericStringStream(const Ch *src) : src_(src), head_(src) {} GenericStringStream(const Ch* src) : src_(src), head_(src) {}
Ch Peek() const { return *src_; } Ch Peek() const { return *src_; }
Ch Take() { return *src_++; } Ch Take() { return *src_++; }
size_t Tell() const { return static_cast<size_t>(src_ - head_); } size_t Tell() const { return static_cast<size_t>(src_ - head_); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() {
RAPIDJSON_ASSERT(false);
return 0;
}
void Put(Ch) { RAPIDJSON_ASSERT(false); } void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) {
RAPIDJSON_ASSERT(false);
return 0;
}
const Ch* src_; //!< Current read position. const Ch* src_; //!< Current read position.
const Ch* head_; //!< Original head of the string. const Ch* head_; //!< Original head of the string.
}; };
template <typename Encoding> template <typename Encoding>
struct StreamTraits<GenericStringStream<Encoding> > { struct StreamTraits<GenericStringStream<Encoding>> {
enum { copyOptimization = 1 }; enum { copyOptimization = 1 };
}; };
//! String stream with UTF8 encoding. //! String stream with UTF8 encoding.
typedef GenericStringStream<UTF8<> > StringStream; typedef GenericStringStream<UTF8<>> StringStream;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// InsituStringStream // InsituStringStream
@ -188,7 +194,7 @@ template <typename Encoding>
struct GenericInsituStringStream { struct GenericInsituStringStream {
typedef typename Encoding::Ch Ch; typedef typename Encoding::Ch Ch;
GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} GenericInsituStringStream(Ch* src) : src_(src), dst_(0), head_(src) {}
// Read // Read
Ch Peek() { return *src_; } Ch Peek() { return *src_; }
@ -196,13 +202,20 @@ struct GenericInsituStringStream {
size_t Tell() { return static_cast<size_t>(src_ - head_); } size_t Tell() { return static_cast<size_t>(src_ - head_); }
// Write // Write
void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } void Put(Ch c) {
RAPIDJSON_ASSERT(dst_ != 0);
*dst_++ = c;
}
Ch* PutBegin() { return dst_ = src_; } Ch* PutBegin() { return dst_ = src_; }
size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); } size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
void Flush() {} void Flush() {}
Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } Ch* Push(size_t count) {
Ch* begin = dst_;
dst_ += count;
return begin;
}
void Pop(size_t count) { dst_ -= count; } void Pop(size_t count) { dst_ -= count; }
Ch* src_; Ch* src_;
@ -211,12 +224,12 @@ struct GenericInsituStringStream {
}; };
template <typename Encoding> template <typename Encoding>
struct StreamTraits<GenericInsituStringStream<Encoding> > { struct StreamTraits<GenericInsituStringStream<Encoding>> {
enum { copyOptimization = 1 }; enum { copyOptimization = 1 };
}; };
//! Insitu string stream with UTF8 encoding. //! Insitu string stream with UTF8 encoding.
typedef GenericInsituStringStream<UTF8<> > InsituStringStream; typedef GenericInsituStringStream<UTF8<>> InsituStringStream;
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_STRINGBUFFER_H_ #ifndef RAPIDJSON_STRINGBUFFER_H_
@ -26,7 +26,7 @@
#if defined(__clang__) #if defined(__clang__)
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(c++98-compat) RAPIDJSON_DIAG_OFF(c++ 98 - compat)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
@ -94,21 +94,21 @@ private:
}; };
//! String buffer with UTF8 encoding //! String buffer with UTF8 encoding
typedef GenericStringBuffer<UTF8<> > StringBuffer; typedef GenericStringBuffer<UTF8<>> StringBuffer;
template<typename Encoding, typename Allocator> template <typename Encoding, typename Allocator>
inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) { inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {
stream.Reserve(count); stream.Reserve(count);
} }
template<typename Encoding, typename Allocator> template <typename Encoding, typename Allocator>
inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) { inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {
stream.PutUnsafe(c); stream.PutUnsafe(c);
} }
//! Implement specialized version of PutN() with memset() for better performance. //! Implement specialized version of PutN() with memset() for better performance.
template<> template <>
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) { inline void PutN(GenericStringBuffer<UTF8<>>& stream, char c, size_t n) {
std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c)); std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
} }

View File

@ -1,5 +1,5 @@
// Tencent is pleased to support the open source community by making RapidJSON available. // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// //
// Licensed under the MIT License (the "License"); you may not use this file except // Licensed under the MIT License (the "License"); you may not use this file except
@ -7,9 +7,9 @@
// //
// http://opensource.org/licenses/MIT // http://opensource.org/licenses/MIT
// //
// Unless required by applicable law or agreed to in writing, software distributed // Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License. // specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_WRITER_H_ #ifndef RAPIDJSON_WRITER_H_
@ -23,7 +23,7 @@
#include "internal/dtoa.h" #include "internal/dtoa.h"
#include "internal/itoa.h" #include "internal/itoa.h"
#include "stringbuffer.h" #include "stringbuffer.h"
#include <new> // placement new #include <new> // placement new
#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
#include <intrin.h> #include <intrin.h>
@ -40,8 +40,8 @@
#ifdef __clang__ #ifdef __clang__
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(unreachable - code)
RAPIDJSON_DIAG_OFF(c++98-compat) RAPIDJSON_DIAG_OFF(c++ 98 - compat)
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
@ -64,10 +64,10 @@ RAPIDJSON_NAMESPACE_BEGIN
//! Combination of writeFlags //! Combination of writeFlags
enum WriteFlag { enum WriteFlag {
kWriteNoFlags = 0, //!< No flags are set. kWriteNoFlags = 0, //!< No flags are set.
kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN. kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN.
kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
}; };
//! JSON writer //! JSON writer
@ -86,7 +86,7 @@ enum WriteFlag {
\tparam StackAllocator Type of allocator for allocating memory of stack. \tparam StackAllocator Type of allocator for allocating memory of stack.
\note implements Handler concept \note implements Handler concept
*/ */
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> template <typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
class Writer { class Writer {
public: public:
typedef typename SourceEncoding::Ch Ch; typedef typename SourceEncoding::Ch Ch;
@ -98,17 +98,12 @@ public:
\param stackAllocator User supplied allocator. If it is null, it will create a private one. \param stackAllocator User supplied allocator. If it is null, it will create a private one.
\param levelDepth Initial capacity of stack. \param levelDepth Initial capacity of stack.
*/ */
explicit explicit Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
explicit explicit Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
Writer(Writer&& rhs) : Writer(Writer&& rhs) : os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {
os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {
rhs.os_ = 0; rhs.os_ = 0;
} }
#endif #endif
@ -179,19 +174,40 @@ public:
*/ */
//@{ //@{
bool Null() { Prefix(kNullType); return EndValue(WriteNull()); } bool Null() {
bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); } Prefix(kNullType);
bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); } return EndValue(WriteNull());
bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); } }
bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); } bool Bool(bool b) {
bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); } Prefix(b ? kTrueType : kFalseType);
return EndValue(WriteBool(b));
}
bool Int(int i) {
Prefix(kNumberType);
return EndValue(WriteInt(i));
}
bool Uint(unsigned u) {
Prefix(kNumberType);
return EndValue(WriteUint(u));
}
bool Int64(int64_t i64) {
Prefix(kNumberType);
return EndValue(WriteInt64(i64));
}
bool Uint64(uint64_t u64) {
Prefix(kNumberType);
return EndValue(WriteUint64(u64));
}
//! Writes the given \c double value to the stream //! Writes the given \c double value to the stream
/*! /*!
\param d The value to be written. \param d The value to be written.
\return Whether it is succeed. \return Whether it is succeed.
*/ */
bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); } bool Double(double d) {
Prefix(kNumberType);
return EndValue(WriteDouble(d));
}
bool RawNumber(const Ch* str, SizeType length, bool copy = false) { bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
RAPIDJSON_ASSERT(str != 0); RAPIDJSON_ASSERT(str != 0);
@ -222,16 +238,15 @@ public:
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
#if RAPIDJSON_HAS_STDSTRING #if RAPIDJSON_HAS_STDSTRING
bool Key(const std::basic_string<Ch>& str) bool Key(const std::basic_string<Ch>& str) {
{ return Key(str.data(), SizeType(str.size()));
return Key(str.data(), SizeType(str.size()));
} }
#endif #endif
bool EndObject(SizeType memberCount = 0) { bool EndObject(SizeType memberCount = 0) {
(void)memberCount; (void)memberCount;
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object
RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value
level_stack_.template Pop<Level>(1); level_stack_.template Pop<Level>(1);
return EndValue(WriteEndObject()); return EndValue(WriteEndObject());
@ -258,7 +273,7 @@ public:
//! Simpler but slower overload. //! Simpler but slower overload.
bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); } bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); }
bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); } bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); }
//@} //@}
//! Write a raw JSON value. //! Write a raw JSON value.
@ -289,23 +304,34 @@ protected:
//! Information for each nested level //! Information for each nested level
struct Level { struct Level {
Level(bool inArray_) : valueCount(0), inArray(inArray_) {} Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
size_t valueCount; //!< number of values in this level size_t valueCount; //!< number of values in this level
bool inArray; //!< true if in array, otherwise in object bool inArray; //!< true if in array, otherwise in object
}; };
bool WriteNull() { bool WriteNull() {
PutReserve(*os_, 4); PutReserve(*os_, 4);
PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; PutUnsafe(*os_, 'n');
PutUnsafe(*os_, 'u');
PutUnsafe(*os_, 'l');
PutUnsafe(*os_, 'l');
return true;
} }
bool WriteBool(bool b) { bool WriteBool(bool b) {
if (b) { if (b) {
PutReserve(*os_, 4); PutReserve(*os_, 4);
PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e'); PutUnsafe(*os_, 't');
PutUnsafe(*os_, 'r');
PutUnsafe(*os_, 'u');
PutUnsafe(*os_, 'e');
} }
else { else {
PutReserve(*os_, 5); PutReserve(*os_, 5);
PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); PutUnsafe(*os_, 'f');
PutUnsafe(*os_, 'a');
PutUnsafe(*os_, 'l');
PutUnsafe(*os_, 's');
PutUnsafe(*os_, 'e');
} }
return true; return true;
} }
@ -352,7 +378,9 @@ protected:
return false; return false;
if (internal::Double(d).IsNan()) { if (internal::Double(d).IsNan()) {
PutReserve(*os_, 3); PutReserve(*os_, 3);
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'N');
PutUnsafe(*os_, 'a');
PutUnsafe(*os_, 'N');
return true; return true;
} }
if (internal::Double(d).Sign()) { if (internal::Double(d).Sign()) {
@ -361,8 +389,14 @@ protected:
} }
else else
PutReserve(*os_, 8); PutReserve(*os_, 8);
PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'I');
PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); PutUnsafe(*os_, 'n');
PutUnsafe(*os_, 'f');
PutUnsafe(*os_, 'i');
PutUnsafe(*os_, 'n');
PutUnsafe(*os_, 'i');
PutUnsafe(*os_, 't');
PutUnsafe(*os_, 'y');
return true; return true;
} }
@ -374,16 +408,16 @@ protected:
return true; return true;
} }
bool WriteString(const Ch* str, SizeType length) { bool WriteString(const Ch* str, SizeType length) {
static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
static const char escape[256] = { static const char escape[256] = {
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 #define Z16 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
//0 1 2 3 4 5 6 7 8 9 A B C D E F //0 1 2 3 4 5 6 7 8 9 A B C D E F
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
Z16, Z16, // 30~4F Z16, Z16, // 30~4F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0, // 50
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
#undef Z16 #undef Z16
}; };
@ -391,7 +425,7 @@ protected:
if (TargetEncoding::supportUnicode) if (TargetEncoding::supportUnicode)
PutReserve(*os_, 2 + length * 6); // "\uxxxx..." PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
else else
PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
PutUnsafe(*os_, '\"'); PutUnsafe(*os_, '\"');
GenericStringStream<SourceEncoding> is(str); GenericStringStream<SourceEncoding> is(str);
@ -406,9 +440,9 @@ protected:
PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'u');
if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]); PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]); PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
PutUnsafe(*os_, hexDigits[(codepoint ) & 15]); PutUnsafe(*os_, hexDigits[(codepoint)&15]);
} }
else { else {
RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
@ -417,18 +451,18 @@ protected:
unsigned lead = (s >> 10) + 0xD800; unsigned lead = (s >> 10) + 0xD800;
unsigned trail = (s & 0x3FF) + 0xDC00; unsigned trail = (s & 0x3FF) + 0xDC00;
PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]); PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]); PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
PutUnsafe(*os_, hexDigits[(lead ) & 15]); PutUnsafe(*os_, hexDigits[(lead)&15]);
PutUnsafe(*os_, '\\'); PutUnsafe(*os_, '\\');
PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'u');
PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]); PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]); PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
PutUnsafe(*os_, hexDigits[(trail ) & 15]); PutUnsafe(*os_, hexDigits[(trail)&15]);
} }
} }
else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) { else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
is.Take(); is.Take();
PutUnsafe(*os_, '\\'); PutUnsafe(*os_, '\\');
PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)])); PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)]));
@ -439,9 +473,7 @@ protected:
PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]); PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
} }
} }
else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) : Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
return false; return false;
} }
PutUnsafe(*os_, '\"'); PutUnsafe(*os_, '\"');
@ -452,19 +484,29 @@ protected:
return RAPIDJSON_LIKELY(is.Tell() < length); return RAPIDJSON_LIKELY(is.Tell() < length);
} }
bool WriteStartObject() { os_->Put('{'); return true; } bool WriteStartObject() {
bool WriteEndObject() { os_->Put('}'); return true; } os_->Put('{');
bool WriteStartArray() { os_->Put('['); return true; } return true;
bool WriteEndArray() { os_->Put(']'); return true; } }
bool WriteEndObject() {
os_->Put('}');
return true;
}
bool WriteStartArray() {
os_->Put('[');
return true;
}
bool WriteEndArray() {
os_->Put(']');
return true;
}
bool WriteRawValue(const Ch* json, size_t length) { bool WriteRawValue(const Ch* json, size_t length) {
PutReserve(*os_, length); PutReserve(*os_, length);
GenericStringStream<SourceEncoding> is(json); GenericStringStream<SourceEncoding> is(json);
while (RAPIDJSON_LIKELY(is.Tell() < length)) { while (RAPIDJSON_LIKELY(is.Tell() < length)) {
RAPIDJSON_ASSERT(is.Peek() != '\0'); RAPIDJSON_ASSERT(is.Peek() != '\0');
if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) : Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
return false; return false;
} }
return true; return true;
@ -475,24 +517,24 @@ protected:
if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
Level* level = level_stack_.template Top<Level>(); Level* level = level_stack_.template Top<Level>();
if (level->valueCount > 0) { if (level->valueCount > 0) {
if (level->inArray) if (level->inArray)
os_->Put(','); // add comma if it is not the first element in array os_->Put(','); // add comma if it is not the first element in array
else // in object else // in object
os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
} }
if (!level->inArray && level->valueCount % 2 == 0) if (!level->inArray && level->valueCount % 2 == 0)
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
level->valueCount++; level->valueCount++;
} }
else { else {
RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
hasRoot_ = true; hasRoot_ = true;
} }
} }
// Flush the value if it is the top level one. // Flush the value if it is the top level one.
bool EndValue(bool ret) { bool EndValue(bool ret) {
if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
Flush(); Flush();
return ret; return ret;
} }
@ -510,39 +552,39 @@ private:
// Full specialization for StringStream to prevent memory copying // Full specialization for StringStream to prevent memory copying
template<> template <>
inline bool Writer<StringBuffer>::WriteInt(int i) { inline bool Writer<StringBuffer>::WriteInt(int i) {
char *buffer = os_->Push(11); char* buffer = os_->Push(11);
const char* end = internal::i32toa(i, buffer); const char* end = internal::i32toa(i, buffer);
os_->Pop(static_cast<size_t>(11 - (end - buffer))); os_->Pop(static_cast<size_t>(11 - (end - buffer)));
return true; return true;
} }
template<> template <>
inline bool Writer<StringBuffer>::WriteUint(unsigned u) { inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
char *buffer = os_->Push(10); char* buffer = os_->Push(10);
const char* end = internal::u32toa(u, buffer); const char* end = internal::u32toa(u, buffer);
os_->Pop(static_cast<size_t>(10 - (end - buffer))); os_->Pop(static_cast<size_t>(10 - (end - buffer)));
return true; return true;
} }
template<> template <>
inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) { inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
char *buffer = os_->Push(21); char* buffer = os_->Push(21);
const char* end = internal::i64toa(i64, buffer); const char* end = internal::i64toa(i64, buffer);
os_->Pop(static_cast<size_t>(21 - (end - buffer))); os_->Pop(static_cast<size_t>(21 - (end - buffer)));
return true; return true;
} }
template<> template <>
inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) { inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
char *buffer = os_->Push(20); char* buffer = os_->Push(20);
const char* end = internal::u64toa(u, buffer); const char* end = internal::u64toa(u, buffer);
os_->Pop(static_cast<size_t>(20 - (end - buffer))); os_->Pop(static_cast<size_t>(20 - (end - buffer)));
return true; return true;
} }
template<> template <>
inline bool Writer<StringBuffer>::WriteDouble(double d) { inline bool Writer<StringBuffer>::WriteDouble(double d) {
if (internal::Double(d).IsNanOrInf()) { if (internal::Double(d).IsNanOrInf()) {
// Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
@ -550,7 +592,9 @@ inline bool Writer<StringBuffer>::WriteDouble(double d) {
return false; return false;
if (internal::Double(d).IsNan()) { if (internal::Double(d).IsNan()) {
PutReserve(*os_, 3); PutReserve(*os_, 3);
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'N');
PutUnsafe(*os_, 'a');
PutUnsafe(*os_, 'N');
return true; return true;
} }
if (internal::Double(d).Sign()) { if (internal::Double(d).Sign()) {
@ -559,19 +603,25 @@ inline bool Writer<StringBuffer>::WriteDouble(double d) {
} }
else else
PutReserve(*os_, 8); PutReserve(*os_, 8);
PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'I');
PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); PutUnsafe(*os_, 'n');
PutUnsafe(*os_, 'f');
PutUnsafe(*os_, 'i');
PutUnsafe(*os_, 'n');
PutUnsafe(*os_, 'i');
PutUnsafe(*os_, 't');
PutUnsafe(*os_, 'y');
return true; return true;
} }
char *buffer = os_->Push(25); char* buffer = os_->Push(25);
char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
os_->Pop(static_cast<size_t>(25 - (end - buffer))); os_->Pop(static_cast<size_t>(25 - (end - buffer)));
return true; return true;
} }
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
template<> template <>
inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) { inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
if (length < 16) if (length < 16)
return RAPIDJSON_LIKELY(is.Tell() < length); return RAPIDJSON_LIKELY(is.Tell() < length);
@ -597,21 +647,21 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
// The rest of string using SIMD // The rest of string using SIMD
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0])); const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&dquote[0]));
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&bslash[0]));
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i*>(&space[0]));
for (; p != endAligned; p += 16) { for (; p != endAligned; p += 16) {
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p)); const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i*>(p));
const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t1 = _mm_cmpeq_epi8(s, dq);
const __m128i t2 = _mm_cmpeq_epi8(s, bs); const __m128i t2 = _mm_cmpeq_epi8(s, bs);
const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x)); unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
SizeType len; SizeType len;
#ifdef _MSC_VER // Find the index of first escaped #ifdef _MSC_VER // Find the index of first escaped
unsigned long offset; unsigned long offset;
_BitScanForward(&offset, r); _BitScanForward(&offset, r);
len = offset; len = offset;
@ -625,14 +675,14 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
p += len; p += len;
break; break;
} }
_mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s); _mm_storeu_si128(reinterpret_cast<__m128i*>(os_->PushUnsafe(16)), s);
} }
is.src_ = p; is.src_ = p;
return RAPIDJSON_LIKELY(is.Tell() < length); return RAPIDJSON_LIKELY(is.Tell() < length);
} }
#elif defined(RAPIDJSON_NEON) #elif defined(RAPIDJSON_NEON)
template<> template <>
inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) { inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
if (length < 16) if (length < 16)
return RAPIDJSON_LIKELY(is.Tell() < length); return RAPIDJSON_LIKELY(is.Tell() < length);
@ -662,15 +712,15 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
const uint8x16_t s3 = vmovq_n_u8(32); const uint8x16_t s3 = vmovq_n_u8(32);
for (; p != endAligned; p += 16) { for (; p != endAligned; p += 16) {
const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p)); const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t*>(p));
uint8x16_t x = vceqq_u8(s, s0); uint8x16_t x = vceqq_u8(s, s0);
x = vorrq_u8(x, vceqq_u8(s, s1)); x = vorrq_u8(x, vceqq_u8(s, s1));
x = vorrq_u8(x, vceqq_u8(s, s2)); x = vorrq_u8(x, vceqq_u8(s, s2));
x = vorrq_u8(x, vcltq_u8(s, s3)); x = vorrq_u8(x, vcltq_u8(s, s3));
x = vrev64q_u8(x); // Rev in 64 x = vrev64q_u8(x); // Rev in 64
uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract uint64_t low = vgetq_lane_u64(vreinterpretq_u64_u8(x), 0); // extract
uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract uint64_t high = vgetq_lane_u64(vreinterpretq_u64_u8(x), 1); // extract
SizeType len = 0; SizeType len = 0;
bool escaped = false; bool escaped = false;
@ -680,12 +730,13 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
len = 8 + (lz >> 3); len = 8 + (lz >> 3);
escaped = true; escaped = true;
} }
} else { }
else {
uint32_t lz = internal::clzll(low); uint32_t lz = internal::clzll(low);
len = lz >> 3; len = lz >> 3;
escaped = true; escaped = true;
} }
if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
char* q = reinterpret_cast<char*>(os_->PushUnsafe(len)); char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
for (size_t i = 0; i < len; i++) for (size_t i = 0; i < len; i++)
q[i] = p[i]; q[i] = p[i];
@ -693,7 +744,7 @@ inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, siz
p += len; p += len;
break; break;
} }
vst1q_u8(reinterpret_cast<uint8_t *>(os_->PushUnsafe(16)), s); vst1q_u8(reinterpret_cast<uint8_t*>(os_->PushUnsafe(16)), s);
} }
is.src_ = p; is.src_ = p;

View File

@ -16,22 +16,15 @@ struct Backoff {
double rand01() { return randDistribution(randGenerator); } double rand01() { return randDistribution(randGenerator); }
Backoff(int64_t min, int64_t max) Backoff(int64_t min, int64_t max)
: minAmount(min) : minAmount(min), maxAmount(max), current(min), fails(0), randGenerator((uint64_t)time(0)) {
, maxAmount(max)
, current(min)
, fails(0)
, randGenerator((uint64_t)time(0))
{
} }
void reset() void reset() {
{
fails = 0; fails = 0;
current = minAmount; current = minAmount;
} }
int64_t nextDelay() int64_t nextDelay() {
{
++fails; ++fails;
int64_t delay = (int64_t)((double)current * 2.0 * rand01()); int64_t delay = (int64_t)((double)current * 2.0 * rand01());
current = std::min(current + delay, maxAmount); current = std::min(current + delay, maxAmount);

View File

@ -11,7 +11,7 @@ int GetProcessId();
struct BaseConnection { struct BaseConnection {
static BaseConnection* Create(); static BaseConnection* Create();
static void Destroy(BaseConnection*&); static void Destroy(BaseConnection*&);
bool isOpen{false}; bool isOpen{ false };
bool Open(); bool Open();
bool Close(); bool Close();
bool Write(const void* data, size_t length); bool Write(const void* data, size_t length);

View File

@ -9,13 +9,12 @@
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h> #include <unistd.h>
int GetProcessId() int GetProcessId() {
{
return ::getpid(); return ::getpid();
} }
struct BaseConnectionUnix : public BaseConnection { struct BaseConnectionUnix : public BaseConnection {
int sock{-1}; int sock{ -1 };
}; };
static BaseConnectionUnix Connection; static BaseConnectionUnix Connection;
@ -26,8 +25,7 @@ static int MsgFlags = MSG_NOSIGNAL;
static int MsgFlags = 0; static int MsgFlags = 0;
#endif #endif
static const char* GetTempPath() static const char* GetTempPath() {
{
const char* temp = getenv("XDG_RUNTIME_DIR"); const char* temp = getenv("XDG_RUNTIME_DIR");
temp = temp ? temp : getenv("TMPDIR"); temp = temp ? temp : getenv("TMPDIR");
temp = temp ? temp : getenv("TMP"); temp = temp ? temp : getenv("TMP");
@ -36,21 +34,18 @@ static const char* GetTempPath()
return temp; return temp;
} }
/*static*/ BaseConnection* BaseConnection::Create() /*static*/ BaseConnection* BaseConnection::Create() {
{
PipeAddr.sun_family = AF_UNIX; PipeAddr.sun_family = AF_UNIX;
return &Connection; return &Connection;
} }
/*static*/ void BaseConnection::Destroy(BaseConnection*& c) /*static*/ void BaseConnection::Destroy(BaseConnection*& c) {
{
auto self = reinterpret_cast<BaseConnectionUnix*>(c); auto self = reinterpret_cast<BaseConnectionUnix*>(c);
self->Close(); self->Close();
c = nullptr; c = nullptr;
} }
bool BaseConnection::Open() bool BaseConnection::Open() {
{
const char* tempPath = GetTempPath(); const char* tempPath = GetTempPath();
auto self = reinterpret_cast<BaseConnectionUnix*>(this); auto self = reinterpret_cast<BaseConnectionUnix*>(this);
self->sock = socket(AF_UNIX, SOCK_STREAM, 0); self->sock = socket(AF_UNIX, SOCK_STREAM, 0);
@ -65,7 +60,7 @@ bool BaseConnection::Open()
for (int pipeNum = 0; pipeNum < 10; ++pipeNum) { for (int pipeNum = 0; pipeNum < 10; ++pipeNum) {
snprintf( snprintf(
PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum); PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum);
int err = connect(self->sock, (const sockaddr*)&PipeAddr, sizeof(PipeAddr)); int err = connect(self->sock, (const sockaddr*)&PipeAddr, sizeof(PipeAddr));
if (err == 0) { if (err == 0) {
self->isOpen = true; self->isOpen = true;
@ -76,8 +71,7 @@ bool BaseConnection::Open()
return false; return false;
} }
bool BaseConnection::Close() bool BaseConnection::Close() {
{
auto self = reinterpret_cast<BaseConnectionUnix*>(this); auto self = reinterpret_cast<BaseConnectionUnix*>(this);
if (self->sock == -1) { if (self->sock == -1) {
return false; return false;
@ -88,8 +82,7 @@ bool BaseConnection::Close()
return true; return true;
} }
bool BaseConnection::Write(const void* data, size_t length) bool BaseConnection::Write(const void* data, size_t length) {
{
auto self = reinterpret_cast<BaseConnectionUnix*>(this); auto self = reinterpret_cast<BaseConnectionUnix*>(this);
if (self->sock == -1) { if (self->sock == -1) {
@ -103,8 +96,7 @@ bool BaseConnection::Write(const void* data, size_t length)
return sentBytes == (ssize_t)length; return sentBytes == (ssize_t)length;
} }
bool BaseConnection::Read(void* data, size_t length) bool BaseConnection::Read(void* data, size_t length) {
{
auto self = reinterpret_cast<BaseConnectionUnix*>(this); auto self = reinterpret_cast<BaseConnectionUnix*>(this);
if (self->sock == -1) { if (self->sock == -1) {

View File

@ -7,38 +7,34 @@
#include <assert.h> #include <assert.h>
#include <windows.h> #include <windows.h>
int GetProcessId() int GetProcessId() {
{
return (int)::GetCurrentProcessId(); return (int)::GetCurrentProcessId();
} }
struct BaseConnectionWin : public BaseConnection { struct BaseConnectionWin : public BaseConnection {
HANDLE pipe{INVALID_HANDLE_VALUE}; HANDLE pipe{ INVALID_HANDLE_VALUE };
}; };
static BaseConnectionWin Connection; static BaseConnectionWin Connection;
/*static*/ BaseConnection* BaseConnection::Create() /*static*/ BaseConnection* BaseConnection::Create() {
{
return &Connection; return &Connection;
} }
/*static*/ void BaseConnection::Destroy(BaseConnection*& c) /*static*/ void BaseConnection::Destroy(BaseConnection*& c) {
{
auto self = reinterpret_cast<BaseConnectionWin*>(c); auto self = reinterpret_cast<BaseConnectionWin*>(c);
self->Close(); self->Close();
c = nullptr; c = nullptr;
} }
bool BaseConnection::Open() bool BaseConnection::Open() {
{ wchar_t pipeName[]{ L"\\\\?\\pipe\\discord-ipc-0" };
wchar_t pipeName[]{L"\\\\?\\pipe\\discord-ipc-0"};
const size_t pipeDigit = sizeof(pipeName) / sizeof(wchar_t) - 2; const size_t pipeDigit = sizeof(pipeName) / sizeof(wchar_t) - 2;
pipeName[pipeDigit] = L'0'; pipeName[pipeDigit] = L'0';
auto self = reinterpret_cast<BaseConnectionWin*>(this); auto self = reinterpret_cast<BaseConnectionWin*>(this);
for (;;) { for (;;) {
self->pipe = ::CreateFileW( self->pipe = ::CreateFileW(
pipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr); pipeName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if (self->pipe != INVALID_HANDLE_VALUE) { if (self->pipe != INVALID_HANDLE_VALUE) {
self->isOpen = true; self->isOpen = true;
return true; return true;
@ -61,8 +57,7 @@ bool BaseConnection::Open()
} }
} }
bool BaseConnection::Close() bool BaseConnection::Close() {
{
auto self = reinterpret_cast<BaseConnectionWin*>(this); auto self = reinterpret_cast<BaseConnectionWin*>(this);
::CloseHandle(self->pipe); ::CloseHandle(self->pipe);
self->pipe = INVALID_HANDLE_VALUE; self->pipe = INVALID_HANDLE_VALUE;
@ -70,8 +65,7 @@ bool BaseConnection::Close()
return true; return true;
} }
bool BaseConnection::Write(const void* data, size_t length) bool BaseConnection::Write(const void* data, size_t length) {
{
if (length == 0) { if (length == 0) {
return true; return true;
} }
@ -90,11 +84,10 @@ bool BaseConnection::Write(const void* data, size_t length)
const DWORD bytesLength = (DWORD)length; const DWORD bytesLength = (DWORD)length;
DWORD bytesWritten = 0; DWORD bytesWritten = 0;
return ::WriteFile(self->pipe, data, bytesLength, &bytesWritten, nullptr) == TRUE && return ::WriteFile(self->pipe, data, bytesLength, &bytesWritten, nullptr) == TRUE &&
bytesWritten == bytesLength; bytesWritten == bytesLength;
} }
bool BaseConnection::Read(void* data, size_t length) bool BaseConnection::Read(void* data, size_t length) {
{
assert(data); assert(data);
if (!data) { if (!data) {
return false; return false;

View File

@ -9,8 +9,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
static bool Mkdir(const char* path) static bool Mkdir(const char* path) {
{
int result = mkdir(path, 0755); int result = mkdir(path, 0755);
if (result == 0) { if (result == 0) {
return true; return true;
@ -22,8 +21,7 @@ static bool Mkdir(const char* path)
} }
// we want to register games so we can run them from Discord client as discord-<appid>:// // we want to register games so we can run them from Discord client as discord-<appid>://
extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command) extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command) {
{
// Add a desktop file and update some mime handlers so that xdg-open does the right thing. // Add a desktop file and update some mime handlers so that xdg-open does the right thing.
const char* home = getenv("HOME"); const char* home = getenv("HOME");
@ -42,15 +40,15 @@ extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const
} }
const char* desktopFileFormat = "[Desktop Entry]\n" const char* desktopFileFormat = "[Desktop Entry]\n"
"Name=Game %s\n" "Name=Game %s\n"
"Exec=%s %%u\n" // note: it really wants that %u in there "Exec=%s %%u\n" // note: it really wants that %u in there
"Type=Application\n" "Type=Application\n"
"NoDisplay=true\n" "NoDisplay=true\n"
"Categories=Discord;Games;\n" "Categories=Discord;Games;\n"
"MimeType=x-scheme-handler/discord-%s;\n"; "MimeType=x-scheme-handler/discord-%s;\n";
char desktopFile[2048]; char desktopFile[2048];
int fileLen = snprintf( int fileLen = snprintf(
desktopFile, sizeof(desktopFile), desktopFileFormat, applicationId, command, applicationId); desktopFile, sizeof(desktopFile), desktopFileFormat, applicationId, command, applicationId);
if (fileLen <= 0) { if (fileLen <= 0) {
return; return;
} }
@ -94,8 +92,7 @@ extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const
} }
extern "C" DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, extern "C" DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId,
const char* steamId) const char* steamId) {
{
char command[256]; char command[256];
sprintf(command, "xdg-open steam://rungameid/%s", steamId); sprintf(command, "xdg-open steam://rungameid/%s", steamId);
Discord_Register(applicationId, command); Discord_Register(applicationId, command);

View File

@ -21,8 +21,7 @@
#ifdef __MINGW32__ #ifdef __MINGW32__
#include <wchar.h> #include <wchar.h>
/// strsafe.h fixes /// strsafe.h fixes
static HRESULT StringCbPrintfW(LPWSTR pszDest, size_t cbDest, LPCWSTR pszFormat, ...) static HRESULT StringCbPrintfW(LPWSTR pszDest, size_t cbDest, LPCWSTR pszFormat, ...) {
{
HRESULT ret; HRESULT ret;
va_list va; va_list va;
va_start(va, pszFormat); va_start(va, pszFormat);
@ -51,8 +50,7 @@ static LSTATUS regset(HKEY hkey,
LPCWSTR name, LPCWSTR name,
DWORD type, DWORD type,
const void* data, const void* data,
DWORD len) DWORD len) {
{
HKEY htkey = hkey, hsubkey = nullptr; HKEY htkey = hkey, hsubkey = nullptr;
LSTATUS ret; LSTATUS ret;
if (subkey && subkey[0]) { if (subkey && subkey[0]) {
@ -67,8 +65,7 @@ static LSTATUS regset(HKEY hkey,
return ret; return ret;
} }
static void Discord_RegisterW(const wchar_t* applicationId, const wchar_t* command) static void Discord_RegisterW(const wchar_t* applicationId, const wchar_t* command) {
{
// https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx // https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx
// we want to register games so we can run them as discord-<appid>:// // we want to register games so we can run them as discord-<appid>://
// Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions. // Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions.
@ -89,14 +86,14 @@ static void Discord_RegisterW(const wchar_t* applicationId, const wchar_t* comma
StringCbPrintfW(protocolName, sizeof(protocolName), L"discord-%s", applicationId); StringCbPrintfW(protocolName, sizeof(protocolName), L"discord-%s", applicationId);
wchar_t protocolDescription[128]; wchar_t protocolDescription[128];
StringCbPrintfW( StringCbPrintfW(
protocolDescription, sizeof(protocolDescription), L"URL:Run game %s protocol", applicationId); protocolDescription, sizeof(protocolDescription), L"URL:Run game %s protocol", applicationId);
wchar_t urlProtocol = 0; wchar_t urlProtocol = 0;
wchar_t keyName[256]; wchar_t keyName[256];
StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%s", protocolName); StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%s", protocolName);
HKEY key; HKEY key;
auto status = auto status =
RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, nullptr, 0, KEY_WRITE, nullptr, &key, nullptr); RegCreateKeyExW(HKEY_CURRENT_USER, keyName, 0, nullptr, 0, KEY_WRITE, nullptr, &key, nullptr);
if (status != ERROR_SUCCESS) { if (status != ERROR_SUCCESS) {
fprintf(stderr, "Error creating key\n"); fprintf(stderr, "Error creating key\n");
return; return;
@ -105,7 +102,7 @@ static void Discord_RegisterW(const wchar_t* applicationId, const wchar_t* comma
LSTATUS result; LSTATUS result;
len = (DWORD)lstrlenW(protocolDescription) + 1; len = (DWORD)lstrlenW(protocolDescription) + 1;
result = result =
RegSetKeyValueW(key, nullptr, nullptr, REG_SZ, protocolDescription, len * sizeof(wchar_t)); RegSetKeyValueW(key, nullptr, nullptr, REG_SZ, protocolDescription, len * sizeof(wchar_t));
if (FAILED(result)) { if (FAILED(result)) {
fprintf(stderr, "Error writing description\n"); fprintf(stderr, "Error writing description\n");
} }
@ -117,22 +114,21 @@ static void Discord_RegisterW(const wchar_t* applicationId, const wchar_t* comma
} }
result = RegSetKeyValueW( result = RegSetKeyValueW(
key, L"DefaultIcon", nullptr, REG_SZ, exeFilePath, (exeLen + 1) * sizeof(wchar_t)); key, L"DefaultIcon", nullptr, REG_SZ, exeFilePath, (exeLen + 1) * sizeof(wchar_t));
if (FAILED(result)) { if (FAILED(result)) {
fprintf(stderr, "Error writing icon\n"); fprintf(stderr, "Error writing icon\n");
} }
len = (DWORD)lstrlenW(openCommand) + 1; len = (DWORD)lstrlenW(openCommand) + 1;
result = RegSetKeyValueW( result = RegSetKeyValueW(
key, L"shell\\open\\command", nullptr, REG_SZ, openCommand, len * sizeof(wchar_t)); key, L"shell\\open\\command", nullptr, REG_SZ, openCommand, len * sizeof(wchar_t));
if (FAILED(result)) { if (FAILED(result)) {
fprintf(stderr, "Error writing command\n"); fprintf(stderr, "Error writing command\n");
} }
RegCloseKey(key); RegCloseKey(key);
} }
extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command) extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command) {
{
wchar_t appId[32]; wchar_t appId[32];
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32); MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
@ -148,8 +144,7 @@ extern "C" DISCORD_EXPORT void Discord_Register(const char* applicationId, const
} }
extern "C" DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, extern "C" DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId,
const char* steamId) const char* steamId) {
{
wchar_t appId[32]; wchar_t appId[32];
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32); MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);

View File

@ -15,16 +15,15 @@
#include <thread> #include <thread>
#endif #endif
constexpr size_t MaxMessageSize{16 * 1024}; constexpr size_t MaxMessageSize{ 16 * 1024 };
constexpr size_t MessageQueueSize{8}; constexpr size_t MessageQueueSize{ 8 };
constexpr size_t JoinQueueSize{8}; constexpr size_t JoinQueueSize{ 8 };
struct QueuedMessage { struct QueuedMessage {
size_t length; size_t length;
char buffer[MaxMessageSize]; char buffer[MaxMessageSize];
void Copy(const QueuedMessage& other) void Copy(const QueuedMessage& other) {
{
length = other.length; length = other.length;
if (length) { if (length) {
memcpy(buffer, other.buffer, length); memcpy(buffer, other.buffer, length);
@ -46,20 +45,20 @@ struct User {
// Rounded way up because I'm paranoid about games breaking from future changes in these sizes // Rounded way up because I'm paranoid about games breaking from future changes in these sizes
}; };
static RpcConnection* Connection{nullptr}; static RpcConnection* Connection{ nullptr };
static DiscordEventHandlers QueuedHandlers{}; static DiscordEventHandlers QueuedHandlers{};
static DiscordEventHandlers Handlers{}; static DiscordEventHandlers Handlers{};
static std::atomic_bool WasJustConnected{false}; static std::atomic_bool WasJustConnected{ false };
static std::atomic_bool WasJustDisconnected{false}; static std::atomic_bool WasJustDisconnected{ false };
static std::atomic_bool GotErrorMessage{false}; static std::atomic_bool GotErrorMessage{ false };
static std::atomic_bool WasJoinGame{false}; static std::atomic_bool WasJoinGame{ false };
static std::atomic_bool WasSpectateGame{false}; static std::atomic_bool WasSpectateGame{ false };
static std::atomic_bool UpdatePresence{false}; static std::atomic_bool UpdatePresence{ false };
static char JoinGameSecret[256]; static char JoinGameSecret[256];
static char SpectateGameSecret[256]; static char SpectateGameSecret[256];
static int LastErrorCode{0}; static int LastErrorCode{ 0 };
static char LastErrorMessage[256]; static char LastErrorMessage[256];
static int LastDisconnectErrorCode{0}; static int LastDisconnectErrorCode{ 0 };
static char LastDisconnectErrorMessage[256]; static char LastDisconnectErrorMessage[256];
static std::mutex PresenceMutex; static std::mutex PresenceMutex;
static std::mutex HandlerMutex; static std::mutex HandlerMutex;
@ -72,24 +71,23 @@ static User connectedUser;
// backoff from 0.5 seconds to 1 minute // backoff from 0.5 seconds to 1 minute
static Backoff ReconnectTimeMs(500, 60 * 1000); static Backoff ReconnectTimeMs(500, 60 * 1000);
static auto NextConnect = std::chrono::system_clock::now(); static auto NextConnect = std::chrono::system_clock::now();
static int Pid{0}; static int Pid{ 0 };
static int Nonce{1}; static int Nonce{ 1 };
#ifndef DISCORD_DISABLE_IO_THREAD #ifndef DISCORD_DISABLE_IO_THREAD
static void Discord_UpdateConnection(void); static void Discord_UpdateConnection(void);
class IoThreadHolder { class IoThreadHolder {
private: private:
std::atomic_bool keepRunning{true}; std::atomic_bool keepRunning{ true };
std::mutex waitForIOMutex; std::mutex waitForIOMutex;
std::condition_variable waitForIOActivity; std::condition_variable waitForIOActivity;
std::thread ioThread; std::thread ioThread;
public: public:
void Start() void Start() {
{
keepRunning.store(true); keepRunning.store(true);
ioThread = std::thread([&]() { ioThread = std::thread([&]() {
const std::chrono::duration<int64_t, std::milli> maxWait{500LL}; const std::chrono::duration<int64_t, std::milli> maxWait{ 500LL };
Discord_UpdateConnection(); Discord_UpdateConnection();
while (keepRunning.load()) { while (keepRunning.load()) {
std::unique_lock<std::mutex> lock(waitForIOMutex); std::unique_lock<std::mutex> lock(waitForIOMutex);
@ -101,8 +99,7 @@ public:
void Notify() { waitForIOActivity.notify_all(); } void Notify() { waitForIOActivity.notify_all(); }
void Stop() void Stop() {
{
keepRunning.exchange(false); keepRunning.exchange(false);
Notify(); Notify();
if (ioThread.joinable()) { if (ioThread.joinable()) {
@ -120,12 +117,11 @@ public:
void Notify() {} void Notify() {}
}; };
#endif // DISCORD_DISABLE_IO_THREAD #endif // DISCORD_DISABLE_IO_THREAD
static IoThreadHolder* IoThread{nullptr}; static IoThreadHolder* IoThread{ nullptr };
static void UpdateReconnectTime() static void UpdateReconnectTime() {
{
NextConnect = std::chrono::system_clock::now() + NextConnect = std::chrono::system_clock::now() +
std::chrono::duration<int64_t, std::milli>{ReconnectTimeMs.nextDelay()}; std::chrono::duration<int64_t, std::milli>{ ReconnectTimeMs.nextDelay() };
} }
#ifdef DISCORD_DISABLE_IO_THREAD #ifdef DISCORD_DISABLE_IO_THREAD
@ -237,19 +233,17 @@ static void Discord_UpdateConnection(void)
} }
} }
static void SignalIOActivity() static void SignalIOActivity() {
{
if (IoThread != nullptr) { if (IoThread != nullptr) {
IoThread->Notify(); IoThread->Notify();
} }
} }
static bool RegisterForEvent(const char* evtName) static bool RegisterForEvent(const char* evtName) {
{
auto qmessage = SendQueue.GetNextAddMessage(); auto qmessage = SendQueue.GetNextAddMessage();
if (qmessage) { if (qmessage) {
qmessage->length = qmessage->length =
JsonWriteSubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName); JsonWriteSubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName);
SendQueue.CommitAdd(); SendQueue.CommitAdd();
SignalIOActivity(); SignalIOActivity();
return true; return true;
@ -257,12 +251,11 @@ static bool RegisterForEvent(const char* evtName)
return false; return false;
} }
static bool DeregisterForEvent(const char* evtName) static bool DeregisterForEvent(const char* evtName) {
{
auto qmessage = SendQueue.GetNextAddMessage(); auto qmessage = SendQueue.GetNextAddMessage();
if (qmessage) { if (qmessage) {
qmessage->length = qmessage->length =
JsonWriteUnsubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName); JsonWriteUnsubscribeCommand(qmessage->buffer, sizeof(qmessage->buffer), Nonce++, evtName);
SendQueue.CommitAdd(); SendQueue.CommitAdd();
SignalIOActivity(); SignalIOActivity();
return true; return true;
@ -273,8 +266,7 @@ static bool DeregisterForEvent(const char* evtName)
extern "C" DISCORD_EXPORT void Discord_Initialize(const char* applicationId, extern "C" DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
DiscordEventHandlers* handlers, DiscordEventHandlers* handlers,
int autoRegister, int autoRegister,
const char* optionalSteamId) const char* optionalSteamId) {
{
IoThread = new (std::nothrow) IoThreadHolder(); IoThread = new (std::nothrow) IoThreadHolder();
if (IoThread == nullptr) { if (IoThread == nullptr) {
return; return;
@ -347,8 +339,7 @@ extern "C" DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
IoThread->Start(); IoThread->Start();
} }
extern "C" DISCORD_EXPORT void Discord_Shutdown(void) extern "C" DISCORD_EXPORT void Discord_Shutdown(void) {
{
if (!Connection) { if (!Connection) {
return; return;
} }
@ -366,24 +357,21 @@ extern "C" DISCORD_EXPORT void Discord_Shutdown(void)
RpcConnection::Destroy(Connection); RpcConnection::Destroy(Connection);
} }
extern "C" DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence) extern "C" DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence) {
{
{ {
std::lock_guard<std::mutex> guard(PresenceMutex); std::lock_guard<std::mutex> guard(PresenceMutex);
QueuedPresence.length = JsonWriteRichPresenceObj( QueuedPresence.length = JsonWriteRichPresenceObj(
QueuedPresence.buffer, sizeof(QueuedPresence.buffer), Nonce++, Pid, presence); QueuedPresence.buffer, sizeof(QueuedPresence.buffer), Nonce++, Pid, presence);
UpdatePresence.exchange(true); UpdatePresence.exchange(true);
} }
SignalIOActivity(); SignalIOActivity();
} }
extern "C" DISCORD_EXPORT void Discord_ClearPresence(void) extern "C" DISCORD_EXPORT void Discord_ClearPresence(void) {
{
Discord_UpdatePresence(nullptr); Discord_UpdatePresence(nullptr);
} }
extern "C" DISCORD_EXPORT void Discord_Respond(const char* userId, /* DISCORD_REPLY_ */ int reply) extern "C" DISCORD_EXPORT void Discord_Respond(const char* userId, /* DISCORD_REPLY_ */ int reply) {
{
// if we are not connected, let's not batch up stale messages for later // if we are not connected, let's not batch up stale messages for later
if (!Connection || !Connection->IsOpen()) { if (!Connection || !Connection->IsOpen()) {
return; return;
@ -391,14 +379,13 @@ extern "C" DISCORD_EXPORT void Discord_Respond(const char* userId, /* DISCORD_RE
auto qmessage = SendQueue.GetNextAddMessage(); auto qmessage = SendQueue.GetNextAddMessage();
if (qmessage) { if (qmessage) {
qmessage->length = qmessage->length =
JsonWriteJoinReply(qmessage->buffer, sizeof(qmessage->buffer), userId, reply, Nonce++); JsonWriteJoinReply(qmessage->buffer, sizeof(qmessage->buffer), userId, reply, Nonce++);
SendQueue.CommitAdd(); SendQueue.CommitAdd();
SignalIOActivity(); SignalIOActivity();
} }
} }
extern "C" DISCORD_EXPORT void Discord_RunCallbacks(void) extern "C" DISCORD_EXPORT void Discord_RunCallbacks(void) {
{
// Note on some weirdness: internally we might connect, get other signals, disconnect any number // Note on some weirdness: internally we might connect, get other signals, disconnect any number
// of times inbetween calls here. Externally, we want the sequence to seem sane, so any other // of times inbetween calls here. Externally, we want the sequence to seem sane, so any other
// signals are book-ended by calls to ready and disconnect. // signals are book-ended by calls to ready and disconnect.
@ -421,10 +408,10 @@ extern "C" DISCORD_EXPORT void Discord_RunCallbacks(void)
if (WasJustConnected.exchange(false)) { if (WasJustConnected.exchange(false)) {
std::lock_guard<std::mutex> guard(HandlerMutex); std::lock_guard<std::mutex> guard(HandlerMutex);
if (Handlers.ready) { if (Handlers.ready) {
DiscordUser du{connectedUser.userId, DiscordUser du{ connectedUser.userId,
connectedUser.username, connectedUser.username,
connectedUser.discriminator, connectedUser.discriminator,
connectedUser.avatar}; connectedUser.avatar };
Handlers.ready(&du); Handlers.ready(&du);
} }
} }
@ -460,7 +447,7 @@ extern "C" DISCORD_EXPORT void Discord_RunCallbacks(void)
{ {
std::lock_guard<std::mutex> guard(HandlerMutex); std::lock_guard<std::mutex> guard(HandlerMutex);
if (Handlers.joinRequest) { if (Handlers.joinRequest) {
DiscordUser du{req->userId, req->username, req->discriminator, req->avatar}; DiscordUser du{ req->userId, req->username, req->discriminator, req->avatar };
Handlers.joinRequest(&du); Handlers.joinRequest(&du);
} }
} }
@ -476,8 +463,7 @@ extern "C" DISCORD_EXPORT void Discord_RunCallbacks(void)
} }
} }
extern "C" DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* newHandlers) extern "C" DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* newHandlers) {
{
if (newHandlers) { if (newHandlers) {
#define HANDLE_EVENT_REGISTRATION(handler_name, event) \ #define HANDLE_EVENT_REGISTRATION(handler_name, event) \
if (!Handlers.handler_name && newHandlers->handler_name) { \ if (!Handlers.handler_name && newHandlers->handler_name) { \

View File

@ -2,7 +2,6 @@
// outsmart GCC's missing-declarations warning // outsmart GCC's missing-declarations warning
BOOL WINAPI DllMain(HMODULE, DWORD, LPVOID); BOOL WINAPI DllMain(HMODULE, DWORD, LPVOID);
BOOL WINAPI DllMain(HMODULE, DWORD, LPVOID) BOOL WINAPI DllMain(HMODULE, DWORD, LPVOID) {
{
return TRUE; return TRUE;
} }

View File

@ -8,15 +8,14 @@
template <typename ElementType, size_t QueueSize> template <typename ElementType, size_t QueueSize>
class MsgQueue { class MsgQueue {
ElementType queue_[QueueSize]; ElementType queue_[QueueSize];
std::atomic_uint nextAdd_{0}; std::atomic_uint nextAdd_{ 0 };
std::atomic_uint nextSend_{0}; std::atomic_uint nextSend_{ 0 };
std::atomic_uint pendingSends_{0}; std::atomic_uint pendingSends_{ 0 };
public: public:
MsgQueue() {} MsgQueue() {}
ElementType* GetNextAddMessage() ElementType* GetNextAddMessage() {
{
// if we are falling behind, bail // if we are falling behind, bail
if (pendingSends_.load() >= QueueSize) { if (pendingSends_.load() >= QueueSize) {
return nullptr; return nullptr;
@ -27,8 +26,7 @@ public:
void CommitAdd() { ++pendingSends_; } void CommitAdd() { ++pendingSends_; }
bool HavePendingSends() const { return pendingSends_.load() != 0; } bool HavePendingSends() const { return pendingSends_.load() != 0; }
ElementType* GetNextSendMessage() ElementType* GetNextSendMessage() {
{
auto index = (nextSend_++) % QueueSize; auto index = (nextSend_++) % QueueSize;
return &queue_[index]; return &queue_[index];
} }

View File

@ -6,22 +6,19 @@
static const int RpcVersion = 1; static const int RpcVersion = 1;
static RpcConnection Instance; static RpcConnection Instance;
/*static*/ RpcConnection* RpcConnection::Create(const char* applicationId) /*static*/ RpcConnection* RpcConnection::Create(const char* applicationId) {
{
Instance.connection = BaseConnection::Create(); Instance.connection = BaseConnection::Create();
StringCopy(Instance.appId, applicationId); StringCopy(Instance.appId, applicationId);
return &Instance; return &Instance;
} }
/*static*/ void RpcConnection::Destroy(RpcConnection*& c) /*static*/ void RpcConnection::Destroy(RpcConnection*& c) {
{
c->Close(); c->Close();
BaseConnection::Destroy(c->connection); BaseConnection::Destroy(c->connection);
c = nullptr; c = nullptr;
} }
void RpcConnection::Open() void RpcConnection::Open() {
{
if (state == State::Connected) { if (state == State::Connected) {
return; return;
} }
@ -46,7 +43,7 @@ void RpcConnection::Open()
else { else {
sendFrame.opcode = Opcode::Handshake; sendFrame.opcode = Opcode::Handshake;
sendFrame.length = (uint32_t)JsonWriteHandshakeObj( sendFrame.length = (uint32_t)JsonWriteHandshakeObj(
sendFrame.message, sizeof(sendFrame.message), RpcVersion, appId); sendFrame.message, sizeof(sendFrame.message), RpcVersion, appId);
if (connection->Write(&sendFrame, sizeof(MessageFrameHeader) + sendFrame.length)) { if (connection->Write(&sendFrame, sizeof(MessageFrameHeader) + sendFrame.length)) {
state = State::SentHandshake; state = State::SentHandshake;
@ -57,8 +54,7 @@ void RpcConnection::Open()
} }
} }
void RpcConnection::Close() void RpcConnection::Close() {
{
if (onDisconnect && (state == State::Connected || state == State::SentHandshake)) { if (onDisconnect && (state == State::Connected || state == State::SentHandshake)) {
onDisconnect(lastErrorCode, lastErrorMessage); onDisconnect(lastErrorCode, lastErrorMessage);
} }
@ -66,8 +62,7 @@ void RpcConnection::Close()
state = State::Disconnected; state = State::Disconnected;
} }
bool RpcConnection::Write(const void* data, size_t length) bool RpcConnection::Write(const void* data, size_t length) {
{
sendFrame.opcode = Opcode::Frame; sendFrame.opcode = Opcode::Frame;
memcpy(sendFrame.message, data, length); memcpy(sendFrame.message, data, length);
sendFrame.length = (uint32_t)length; sendFrame.length = (uint32_t)length;
@ -78,8 +73,7 @@ bool RpcConnection::Write(const void* data, size_t length)
return true; return true;
} }
bool RpcConnection::Read(JsonDocument& message) bool RpcConnection::Read(JsonDocument& message) {
{
if (state != State::Connected && state != State::SentHandshake) { if (state != State::Connected && state != State::SentHandshake) {
return false; return false;
} }

View File

@ -38,12 +38,12 @@ struct RpcConnection {
Connected, Connected,
}; };
BaseConnection* connection{nullptr}; BaseConnection* connection{ nullptr };
State state{State::Disconnected}; State state{ State::Disconnected };
void (*onConnect)(JsonDocument& message){nullptr}; void (*onConnect)(JsonDocument& message){ nullptr };
void (*onDisconnect)(int errorCode, const char* message){nullptr}; void (*onDisconnect)(int errorCode, const char* message){ nullptr };
char appId[64]{}; char appId[64]{};
int lastErrorCode{0}; int lastErrorCode{ 0 };
char lastErrorMessage[256]{}; char lastErrorMessage[256]{};
RpcConnection::MessageFrame sendFrame; RpcConnection::MessageFrame sendFrame;

View File

@ -3,8 +3,7 @@
#include "discord_rpc.h" #include "discord_rpc.h"
template <typename T> template <typename T>
void NumberToString(char* dest, T number) void NumberToString(char* dest, T number) {
{
if (!number) { if (!number) {
*dest++ = '0'; *dest++ = '0';
*dest++ = 0; *dest++ = 0;
@ -29,22 +28,19 @@ void NumberToString(char* dest, T number)
// it's ever so slightly faster to not have to strlen the key // it's ever so slightly faster to not have to strlen the key
template <typename T> template <typename T>
void WriteKey(JsonWriter& w, T& k) void WriteKey(JsonWriter& w, T& k) {
{
w.Key(k, sizeof(T) - 1); w.Key(k, sizeof(T) - 1);
} }
struct WriteObject { struct WriteObject {
JsonWriter& writer; JsonWriter& writer;
WriteObject(JsonWriter& w) WriteObject(JsonWriter& w)
: writer(w) : writer(w) {
{
writer.StartObject(); writer.StartObject();
} }
template <typename T> template <typename T>
WriteObject(JsonWriter& w, T& name) WriteObject(JsonWriter& w, T& name)
: writer(w) : writer(w) {
{
WriteKey(writer, name); WriteKey(writer, name);
writer.StartObject(); writer.StartObject();
} }
@ -55,8 +51,7 @@ struct WriteArray {
JsonWriter& writer; JsonWriter& writer;
template <typename T> template <typename T>
WriteArray(JsonWriter& w, T& name) WriteArray(JsonWriter& w, T& name)
: writer(w) : writer(w) {
{
WriteKey(writer, name); WriteKey(writer, name);
writer.StartArray(); writer.StartArray();
} }
@ -64,16 +59,14 @@ struct WriteArray {
}; };
template <typename T> template <typename T>
void WriteOptionalString(JsonWriter& w, T& k, const char* value) void WriteOptionalString(JsonWriter& w, T& k, const char* value) {
{
if (value && value[0]) { if (value && value[0]) {
w.Key(k, sizeof(T) - 1); w.Key(k, sizeof(T) - 1);
w.String(value); w.String(value);
} }
} }
static void JsonWriteNonce(JsonWriter& writer, int nonce) static void JsonWriteNonce(JsonWriter& writer, int nonce) {
{
WriteKey(writer, "nonce"); WriteKey(writer, "nonce");
char nonceBuffer[32]; char nonceBuffer[32];
NumberToString(nonceBuffer, nonce); NumberToString(nonceBuffer, nonce);
@ -84,8 +77,7 @@ size_t JsonWriteRichPresenceObj(char* dest,
size_t maxLen, size_t maxLen,
int nonce, int nonce,
int pid, int pid,
const DiscordRichPresence* presence) const DiscordRichPresence* presence) {
{
JsonWriter writer(dest, maxLen); JsonWriter writer(dest, maxLen);
{ {
@ -167,8 +159,7 @@ size_t JsonWriteRichPresenceObj(char* dest,
return writer.Size(); return writer.Size();
} }
size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* applicationId) size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* applicationId) {
{
JsonWriter writer(dest, maxLen); JsonWriter writer(dest, maxLen);
{ {
@ -182,8 +173,7 @@ size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char*
return writer.Size(); return writer.Size();
} }
size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName) size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName) {
{
JsonWriter writer(dest, maxLen); JsonWriter writer(dest, maxLen);
{ {
@ -201,8 +191,7 @@ size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const cha
return writer.Size(); return writer.Size();
} }
size_t JsonWriteUnsubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName) size_t JsonWriteUnsubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName) {
{
JsonWriter writer(dest, maxLen); JsonWriter writer(dest, maxLen);
{ {
@ -220,8 +209,7 @@ size_t JsonWriteUnsubscribeCommand(char* dest, size_t maxLen, int nonce, const c
return writer.Size(); return writer.Size();
} }
size_t JsonWriteJoinReply(char* dest, size_t maxLen, const char* userId, int reply, int nonce) size_t JsonWriteJoinReply(char* dest, size_t maxLen, const char* userId, int reply, int nonce) {
{
JsonWriter writer(dest, maxLen); JsonWriter writer(dest, maxLen);
{ {

View File

@ -22,8 +22,7 @@
// if only there was a standard library function for this // if only there was a standard library function for this
template <size_t Len> template <size_t Len>
inline size_t StringCopy(char (&dest)[Len], const char* src) inline size_t StringCopy(char (&dest)[Len], const char* src) {
{
if (!src || !Len) { if (!src || !Len) {
return 0; return 0;
} }
@ -58,18 +57,14 @@ class LinearAllocator {
public: public:
char* buffer_; char* buffer_;
char* end_; char* end_;
LinearAllocator() LinearAllocator() {
{
assert(0); // needed for some default case in rapidjson, should not use assert(0); // needed for some default case in rapidjson, should not use
} }
LinearAllocator(char* buffer, size_t size) LinearAllocator(char* buffer, size_t size)
: buffer_(buffer) : buffer_(buffer), end_(buffer + size) {
, end_(buffer + size)
{
} }
static const bool kNeedFree = false; static const bool kNeedFree = false;
void* Malloc(size_t size) void* Malloc(size_t size) {
{
char* res = buffer_; char* res = buffer_;
buffer_ += size; buffer_ += size;
if (buffer_ > end_) { if (buffer_ > end_) {
@ -78,8 +73,7 @@ public:
} }
return res; return res;
} }
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
{
if (newSize == 0) { if (newSize == 0) {
return nullptr; return nullptr;
} }
@ -90,8 +84,7 @@ public:
(void)(originalSize); (void)(originalSize);
return Malloc(newSize); return Malloc(newSize);
} }
static void Free(void* ptr) static void Free(void* ptr) {
{
/* shrug */ /* shrug */
(void)ptr; (void)ptr;
} }
@ -102,8 +95,7 @@ class FixedLinearAllocator : public LinearAllocator {
public: public:
char fixedBuffer_[Size]; char fixedBuffer_[Size];
FixedLinearAllocator() FixedLinearAllocator()
: LinearAllocator(fixedBuffer_, Size) : LinearAllocator(fixedBuffer_, Size) {
{
} }
static const bool kNeedFree = false; static const bool kNeedFree = false;
}; };
@ -117,14 +109,10 @@ public:
char* current_; char* current_;
DirectStringBuffer(char* buffer, size_t maxLen) DirectStringBuffer(char* buffer, size_t maxLen)
: buffer_(buffer) : buffer_(buffer), end_(buffer + maxLen), current_(buffer) {
, end_(buffer + maxLen)
, current_(buffer)
{
} }
void Put(char c) void Put(char c) {
{
if (current_ < end_) { if (current_ < end_) {
*current_++ = c; *current_++ = c;
} }
@ -140,17 +128,14 @@ using UTF8 = rapidjson::UTF8<char>;
using StackAllocator = FixedLinearAllocator<2048>; using StackAllocator = FixedLinearAllocator<2048>;
constexpr size_t WriterNestingLevels = 2048 / (2 * sizeof(size_t)); constexpr size_t WriterNestingLevels = 2048 / (2 * sizeof(size_t));
using JsonWriterBase = using JsonWriterBase =
rapidjson::Writer<DirectStringBuffer, UTF8, UTF8, StackAllocator, rapidjson::kWriteNoFlags>; rapidjson::Writer<DirectStringBuffer, UTF8, UTF8, StackAllocator, rapidjson::kWriteNoFlags>;
class JsonWriter : public JsonWriterBase { class JsonWriter : public JsonWriterBase {
public: public:
DirectStringBuffer stringBuffer_; DirectStringBuffer stringBuffer_;
StackAllocator stackAlloc_; StackAllocator stackAlloc_;
JsonWriter(char* dest, size_t maxLen) JsonWriter(char* dest, size_t maxLen)
: JsonWriterBase(stringBuffer_, &stackAlloc_, WriterNestingLevels) : JsonWriterBase(stringBuffer_, &stackAlloc_, WriterNestingLevels), stringBuffer_(dest, maxLen), stackAlloc_() {
, stringBuffer_(dest, maxLen)
, stackAlloc_()
{
} }
size_t Size() const { return stringBuffer_.GetSize(); } size_t Size() const { return stringBuffer_.GetSize(); }
@ -167,20 +152,17 @@ public:
PoolAllocator poolAllocator_; PoolAllocator poolAllocator_;
StackAllocator stackAllocator_; StackAllocator stackAllocator_;
JsonDocument() JsonDocument()
: JsonDocumentBase(rapidjson::kObjectType, : JsonDocumentBase(rapidjson::kObjectType,
&poolAllocator_, &poolAllocator_,
sizeof(stackAllocator_.fixedBuffer_), sizeof(stackAllocator_.fixedBuffer_),
&stackAllocator_) &stackAllocator_),
, poolAllocator_(parseBuffer_, sizeof(parseBuffer_), kDefaultChunkCapacity, &mallocAllocator_) poolAllocator_(parseBuffer_, sizeof(parseBuffer_), kDefaultChunkCapacity, &mallocAllocator_), stackAllocator_() {
, stackAllocator_()
{
} }
}; };
using JsonValue = rapidjson::GenericValue<UTF8, PoolAllocator>; using JsonValue = rapidjson::GenericValue<UTF8, PoolAllocator>;
inline JsonValue* GetObjMember(JsonValue* obj, const char* name) inline JsonValue* GetObjMember(JsonValue* obj, const char* name) {
{
if (obj) { if (obj) {
auto member = obj->FindMember(name); auto member = obj->FindMember(name);
if (member != obj->MemberEnd() && member->value.IsObject()) { if (member != obj->MemberEnd() && member->value.IsObject()) {
@ -190,8 +172,7 @@ inline JsonValue* GetObjMember(JsonValue* obj, const char* name)
return nullptr; return nullptr;
} }
inline int GetIntMember(JsonValue* obj, const char* name, int notFoundDefault = 0) inline int GetIntMember(JsonValue* obj, const char* name, int notFoundDefault = 0) {
{
if (obj) { if (obj) {
auto member = obj->FindMember(name); auto member = obj->FindMember(name);
if (member != obj->MemberEnd() && member->value.IsInt()) { if (member != obj->MemberEnd() && member->value.IsInt()) {
@ -203,8 +184,7 @@ inline int GetIntMember(JsonValue* obj, const char* name, int notFoundDefault =
inline const char* GetStrMember(JsonValue* obj, inline const char* GetStrMember(JsonValue* obj,
const char* name, const char* name,
const char* notFoundDefault = nullptr) const char* notFoundDefault = nullptr) {
{
if (obj) { if (obj) {
auto member = obj->FindMember(name); auto member = obj->FindMember(name);
if (member != obj->MemberEnd() && member->value.IsString()) { if (member != obj->MemberEnd() && member->value.IsString()) {