Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • scs/ipaaca
  • ramin.yaghoubzadeh/ipaaca
2 results
Show changes
Showing
with 2323 additions and 1107 deletions
// Copyright (C) 2011 Milo Yip // 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.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_ERROR_ERROR_H__ #ifndef RAPIDJSON_ERROR_ERROR_H_
#define RAPIDJSON_ERROR_ERROR_H__ #define RAPIDJSON_ERROR_ERROR_H_
#include "../rapidjson.h"
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
#endif
/*! \file error.h */ /*! \file error.h */
...@@ -85,7 +86,7 @@ enum ParseErrorCode { ...@@ -85,7 +86,7 @@ enum ParseErrorCode {
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)
...@@ -103,7 +104,9 @@ enum ParseErrorCode { ...@@ -103,7 +104,9 @@ enum ParseErrorCode {
\see GenericReader::Parse, GenericDocument::Parse \see GenericReader::Parse, GenericDocument::Parse
*/ */
struct ParseResult { struct ParseResult {
//!! Unspecified boolean type
typedef bool (ParseResult::*BooleanType)() const;
public:
//! Default constructor, no error. //! Default constructor, no error.
ParseResult() : code_(kParseErrorNone), offset_(0) {} ParseResult() : code_(kParseErrorNone), offset_(0) {}
//! Constructor to set an error. //! Constructor to set an error.
...@@ -114,8 +117,8 @@ struct ParseResult { ...@@ -114,8 +117,8 @@ struct ParseResult {
//! Get the error offset, if \ref IsError(), 0 otherwise. //! Get the error offset, if \ref IsError(), 0 otherwise.
size_t Offset() const { return offset_; } size_t Offset() const { return offset_; }
//! Conversion to \c bool, returns \c true, iff !\ref IsError(). //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError().
operator bool() const { return !IsError(); } operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; }
//! Whether the result is an error. //! Whether the result is an error.
bool IsError() const { return code_ != kParseErrorNone; } bool IsError() const { return code_ != kParseErrorNone; }
...@@ -123,6 +126,10 @@ struct ParseResult { ...@@ -123,6 +126,10 @@ struct ParseResult {
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!=(ParseErrorCode code) const { return !(*this == 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.
...@@ -145,6 +152,65 @@ private: ...@@ -145,6 +152,65 @@ private:
*/ */
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
///////////////////////////////////////////////////////////////////////////////
// ValidateErrorCode
//! Error codes when validating.
/*! \ingroup RAPIDJSON_ERRORS
\see GenericSchemaValidator
*/
enum ValidateErrorCode {
kValidateErrors = -1, //!< Top level error code when kValidateContinueOnErrorsFlag set.
kValidateErrorNone = 0, //!< No error.
kValidateErrorMultipleOf, //!< Number is not a multiple of the 'multipleOf' value.
kValidateErrorMaximum, //!< Number is greater than the 'maximum' value.
kValidateErrorExclusiveMaximum, //!< Number is greater than or equal to the 'maximum' value.
kValidateErrorMinimum, //!< Number is less than the 'minimum' value.
kValidateErrorExclusiveMinimum, //!< Number is less than or equal to the 'minimum' value.
kValidateErrorMaxLength, //!< String is longer than the 'maxLength' value.
kValidateErrorMinLength, //!< String is longer than the 'maxLength' value.
kValidateErrorPattern, //!< String does not match the 'pattern' regular expression.
kValidateErrorMaxItems, //!< Array is longer than the 'maxItems' value.
kValidateErrorMinItems, //!< Array is shorter than the 'minItems' value.
kValidateErrorUniqueItems, //!< Array has duplicate items but 'uniqueItems' is true.
kValidateErrorAdditionalItems, //!< Array has additional items that are not allowed by the schema.
kValidateErrorMaxProperties, //!< Object has more members than 'maxProperties' value.
kValidateErrorMinProperties, //!< Object has less members than 'minProperties' value.
kValidateErrorRequired, //!< Object is missing one or more members required by the schema.
kValidateErrorAdditionalProperties, //!< Object has additional members that are not allowed by the schema.
kValidateErrorPatternProperties, //!< See other errors.
kValidateErrorDependencies, //!< Object has missing property or schema dependencies.
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..
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'.
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'.
kValidateErrorNot //!< Property matched the sub-schema specified by 'not'.
};
//! Function pointer type of GetValidateError().
/*! \ingroup RAPIDJSON_ERRORS
This is the prototype for \c GetValidateError_X(), where \c X is a locale.
User can dynamically change locale in runtime, e.g.:
\code
GetValidateErrorFunc GetValidateError = GetValidateError_En; // or whatever
const RAPIDJSON_ERROR_CHARTYPE* s = GetValidateError(validator.GetInvalidSchemaCode());
\endcode
*/
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetValidateErrorFunc)(ValidateErrorCode);
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ERROR_ERROR_H__ #ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_ERROR_ERROR_H_
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// of this software and associated documentation files (the "Software"), to deal //
// in the Software without restriction, including without limitation the rights // Licensed under the MIT License (the "License"); you may not use this file except
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // in compliance with the License. You may obtain a copy of the License at
// copies of the Software, and to permit persons to whom the Software is //
// furnished to do so, subject to the following conditions: // http://opensource.org/licenses/MIT
// //
// The above copyright notice and this permission notice shall be included in // Unless required by applicable law or agreed to in writing, software distributed
// all copies or substantial portions of the Software. // 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
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // specific language governing permissions and limitations under the License.
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #ifndef RAPIDJSON_FILEREADSTREAM_H_
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #define RAPIDJSON_FILEREADSTREAM_H_
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN #include "stream.h"
// THE SOFTWARE. #include <cstdio>
#ifndef RAPIDJSON_FILEREADSTREAM_H_ #ifdef __clang__
#define RAPIDJSON_FILEREADSTREAM_H_ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
#include "rapidjson.h" RAPIDJSON_DIAG_OFF(unreachable-code)
#include <cstdio> RAPIDJSON_DIAG_OFF(missing-noreturn)
#endif
RAPIDJSON_NAMESPACE_BEGIN
RAPIDJSON_NAMESPACE_BEGIN
//! File byte stream for input using fread().
/*! //! File byte stream for input using fread().
\note implements Stream concept /*!
*/ \note implements Stream concept
class FileReadStream { */
public: class FileReadStream {
typedef char Ch; //!< Character type (byte). public:
typedef char Ch; //!< Character type (byte).
//! Constructor.
/*! //! Constructor.
\param fp File pointer opened for read. /*!
\param buffer user-supplied buffer. \param fp File pointer opened for read.
\param bufferSize size of buffer in bytes. Must >=4 bytes. \param buffer user-supplied buffer.
*/ \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) { */
RAPIDJSON_ASSERT(fp_ != 0); 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(bufferSize >= 4); RAPIDJSON_ASSERT(fp_ != 0);
Read(); RAPIDJSON_ASSERT(bufferSize >= 4);
} Read();
}
Ch Peek() const { return *current_; }
Ch Take() { Ch c = *current_; Read(); return c; } Ch Peek() const { return *current_; }
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); } Ch Take() { Ch c = *current_; Read(); return c; }
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
// Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); } // Not implemented
void Flush() { RAPIDJSON_ASSERT(false); } void Put(Ch) { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } void Flush() { RAPIDJSON_ASSERT(false); }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// For encoding detection only.
const Ch* Peek4() const { // For encoding detection only.
return (current_ + 4 <= bufferLast_) ? current_ : 0; const Ch* Peek4() const {
} return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
}
private:
void Read() { private:
if (current_ < bufferLast_) void Read() {
++current_; if (current_ < bufferLast_)
else if (!eof_) { ++current_;
count_ += readCount_; else if (!eof_) {
readCount_ = fread(buffer_, 1, bufferSize_, fp_); count_ += readCount_;
bufferLast_ = buffer_ + readCount_ - 1; readCount_ = std::fread(buffer_, 1, bufferSize_, fp_);
current_ = buffer_; bufferLast_ = buffer_ + readCount_ - 1;
current_ = buffer_;
if (readCount_ < bufferSize_) {
buffer_[readCount_] = '\0'; if (readCount_ < bufferSize_) {
++bufferLast_; buffer_[readCount_] = '\0';
eof_ = true; ++bufferLast_;
} eof_ = true;
} }
} }
}
std::FILE* fp_;
Ch *buffer_; std::FILE* fp_;
size_t bufferSize_; Ch *buffer_;
Ch *bufferLast_; size_t bufferSize_;
Ch *current_; Ch *bufferLast_;
size_t readCount_; Ch *current_;
size_t count_; //!< Number of characters read size_t readCount_;
bool eof_; size_t count_; //!< Number of characters read
}; bool eof_;
};
RAPIDJSON_NAMESPACE_END
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_FILESTREAM_H_
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_FILESTREAM_H_
// Copyright (C) 2011 Milo Yip
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_FILESTREAM_H_
#define RAPIDJSON_FILESTREAM_H_
#include "rapidjson.h"
#include <cstdio>
RAPIDJSON_NAMESPACE_BEGIN
//! (Deprecated) Wrapper of C file stream for input or output.
/*!
This simple wrapper does not check the validity of the stream.
\note implements Stream concept
\note deprecated: This was only for basic testing in version 0.1, it is found that the performance is very low by using fgetc(). Use FileReadStream instead.
*/
class FileStream {
public:
typedef char Ch; //!< Character type. Only support char.
FileStream(std::FILE* fp) : fp_(fp), current_('\0'), count_(0) { Read(); }
char Peek() const { return current_; }
char Take() { char c = current_; Read(); return c; }
size_t Tell() const { return count_; }
void Put(char c) { fputc(c, fp_); }
void Flush() { fflush(fp_); }
// Not implemented
char* PutBegin() { return 0; }
size_t PutEnd(char*) { return 0; }
private:
// Prohibit copy constructor & assignment operator.
FileStream(const FileStream&);
FileStream& operator=(const FileStream&);
void Read() {
RAPIDJSON_ASSERT(fp_ != 0);
int c = fgetc(fp_);
if (c != EOF) {
current_ = (char)c;
count_++;
}
else if (current_ != '\0')
current_ = '\0';
}
std::FILE* fp_;
char current_;
size_t count_;
};
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_FILESTREAM_H_
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// of this software and associated documentation files (the "Software"), to deal //
// in the Software without restriction, including without limitation the rights // Licensed under the MIT License (the "License"); you may not use this file except
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // in compliance with the License. You may obtain a copy of the License at
// copies of the Software, and to permit persons to whom the Software is //
// furnished to do so, subject to the following conditions: // http://opensource.org/licenses/MIT
// //
// The above copyright notice and this permission notice shall be included in // Unless required by applicable law or agreed to in writing, software distributed
// all copies or substantial portions of the Software. // 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
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // specific language governing permissions and limitations under the License.
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #ifndef RAPIDJSON_FILEWRITESTREAM_H_
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #define RAPIDJSON_FILEWRITESTREAM_H_
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN #include "stream.h"
// THE SOFTWARE. #include <cstdio>
#ifndef RAPIDJSON_FILEWRITESTREAM_H_ #ifdef __clang__
#define RAPIDJSON_FILEWRITESTREAM_H_ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(unreachable-code)
#include "rapidjson.h" #endif
#include <cstdio>
RAPIDJSON_NAMESPACE_BEGIN
RAPIDJSON_NAMESPACE_BEGIN
//! Wrapper of C file stream for output using fwrite().
//! Wrapper of C file stream for input using fread(). /*!
/*! \note implements Stream concept
\note implements Stream concept */
*/ 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();
*current_++ = c;
*current_++ = c; }
}
void PutN(char c, size_t n) {
void PutN(char c, size_t n) { size_t avail = static_cast<size_t>(bufferEnd_ - current_);
size_t avail = static_cast<size_t>(bufferEnd_ - current_); while (n > avail) {
while (n > avail) { std::memset(current_, c, avail);
std::memset(current_, c, avail); current_ += avail;
current_ += avail; Flush();
Flush(); n -= avail;
n -= avail; avail = static_cast<size_t>(bufferEnd_ - current_);
avail = static_cast<size_t>(bufferEnd_ - current_); }
}
if (n > 0) {
if (n > 0) { std::memset(current_, c, n);
std::memset(current_, c, n); current_ += n;
current_ += n; }
} }
}
void Flush() {
void Flush() { if (current_ != buffer_) {
if (current_ != buffer_) { size_t result = std::fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_); if (result < static_cast<size_t>(current_ - buffer_)) {
current_ = buffer_; // failure deliberately ignored at this time
} // added to avoid warn_unused_result build errors
} }
current_ = buffer_;
// Not implemented }
char Peek() const { RAPIDJSON_ASSERT(false); return 0; } }
char Take() { RAPIDJSON_ASSERT(false); return 0; }
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } // Not implemented
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } char Peek() const { 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; }
private: char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
// Prohibit copy constructor & assignment operator. size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
FileWriteStream(const FileWriteStream&);
FileWriteStream& operator=(const FileWriteStream&); private:
// Prohibit copy constructor & assignment operator.
std::FILE* fp_; FileWriteStream(const FileWriteStream&);
char *buffer_; FileWriteStream& operator=(const FileWriteStream&);
char *bufferEnd_;
char *current_; std::FILE* fp_;
}; char *buffer_;
char *bufferEnd_;
//! Implement specialized version of PutN() with memset() for better performance. char *current_;
template<> };
inline void PutN(FileWriteStream& stream, char c, size_t n) {
stream.PutN(c, n); //! Implement specialized version of PutN() with memset() for better performance.
} template<>
inline void PutN(FileWriteStream& stream, char c, size_t n) {
RAPIDJSON_NAMESPACE_END stream.PutN(c, n);
}
#endif // RAPIDJSON_FILESTREAM_H_
RAPIDJSON_NAMESPACE_END
#ifdef __clang__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_FILESTREAM_H_
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FWD_H_
#define RAPIDJSON_FWD_H_
#include "rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
// encodings.h
template<typename CharType> struct UTF8;
template<typename CharType> struct UTF16;
template<typename CharType> struct UTF16BE;
template<typename CharType> struct UTF16LE;
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>
struct Transcoder;
// allocators.h
class CrtAllocator;
template <typename BaseAllocator>
class MemoryPoolAllocator;
// stream.h
template <typename Encoding>
struct GenericStringStream;
typedef GenericStringStream<UTF8<char> > StringStream;
template <typename Encoding>
struct GenericInsituStringStream;
typedef GenericInsituStringStream<UTF8<char> > InsituStringStream;
// stringbuffer.h
template <typename Encoding, typename Allocator>
class GenericStringBuffer;
typedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;
// filereadstream.h
class FileReadStream;
// filewritestream.h
class FileWriteStream;
// memorybuffer.h
template <typename Allocator>
struct GenericMemoryBuffer;
typedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;
// memorystream.h
struct MemoryStream;
// reader.h
template<typename Encoding, typename Derived>
struct BaseReaderHandler;
template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>
class GenericReader;
typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
// writer.h
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
class Writer;
// prettywriter.h
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
class PrettyWriter;
// document.h
template <typename Encoding, typename Allocator>
class GenericMember;
template <bool Const, typename Encoding, typename Allocator>
class GenericMemberIterator;
template<typename CharType>
struct GenericStringRef;
template <typename Encoding, typename Allocator>
class GenericValue;
typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;
template <typename Encoding, typename Allocator, typename StackAllocator>
class GenericDocument;
typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;
// pointer.h
template <typename ValueType, typename Allocator>
class GenericPointer;
typedef GenericPointer<Value, CrtAllocator> Pointer;
// schema.h
template <typename SchemaDocumentType>
class IGenericRemoteSchemaDocumentProvider;
template <typename ValueT, typename Allocator>
class GenericSchemaDocument;
typedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;
typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
template <
typename SchemaDocumentType,
typename OutputHandler,
typename StateAllocator>
class GenericSchemaValidator;
typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_RAPIDJSONFWD_H_
// Copyright (C) 2011 Milo Yip // 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.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_BIGINTEGER_H_ #ifndef RAPIDJSON_BIGINTEGER_H_
#define RAPIDJSON_BIGINTEGER_H_ #define RAPIDJSON_BIGINTEGER_H_
#include "../rapidjson.h" #include "../rapidjson.h"
#if defined(_MSC_VER) && defined(_M_AMD64) #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && defined(_M_AMD64)
#include <intrin.h> // for _umul128 #include <intrin.h> // for _umul128
#pragma intrinsic(_umul128)
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
...@@ -56,7 +51,16 @@ public: ...@@ -56,7 +51,16 @@ public:
if (length > 0) if (length > 0)
AppendDecimal64(decimals + i, decimals + i + length); 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));
}
return *this;
}
BigInteger& operator=(uint64_t u) { BigInteger& operator=(uint64_t u) {
digits_[0] = u; digits_[0] = u;
count_ = 1; count_ = 1;
...@@ -103,7 +107,7 @@ public: ...@@ -103,7 +107,7 @@ public:
if (u == 1) return *this; if (u == 1) return *this;
if (*this == 1) return *this = u; if (*this == 1) return *this = u;
uint32_t k = 0; uint64_t k = 0;
for (size_t i = 0; i < count_; i++) { for (size_t i = 0; i < count_; i++) {
const uint64_t c = digits_[i] >> 32; const uint64_t c = digits_[i] >> 32;
const uint64_t d = digits_[i] & 0xFFFFFFFF; const uint64_t d = digits_[i] & 0xFFFFFFFF;
...@@ -129,7 +133,7 @@ public: ...@@ -129,7 +133,7 @@ public:
RAPIDJSON_ASSERT(count_ + offset <= kCapacity); RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
if (interShift == 0) { if (interShift == 0) {
std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type)); std::memmove(digits_ + offset, digits_, count_ * sizeof(Type));
count_ += offset; count_ += offset;
} }
else { else {
...@@ -148,7 +152,7 @@ public: ...@@ -148,7 +152,7 @@ public:
} }
bool operator==(const BigInteger& rhs) const { bool operator==(const BigInteger& rhs) const {
return count_ == rhs.count_ && memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0; return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
} }
bool operator==(const Type rhs) const { bool operator==(const Type rhs) const {
...@@ -172,19 +176,16 @@ public: ...@@ -172,19 +176,16 @@ public:
}; };
if (exp == 0) return *this; if (exp == 0) return *this;
for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27 for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
for (; exp >= 13; exp -= 13) *this *= 1220703125u; // 5^13 for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
if (exp > 0) *this *= kPow5[exp - 1]; if (exp > 0) *this *= kPow5[exp - 1];
return *this; return *this;
} }
// Compute absolute difference of this and rhs. // Compute absolute difference of this and rhs.
// Return false if this < rhs // Assume this != rhs
bool Difference(const BigInteger& rhs, BigInteger* out) const { bool Difference(const BigInteger& rhs, BigInteger* out) const {
int cmp = Compare(rhs); int cmp = Compare(rhs);
if (cmp == 0) { RAPIDJSON_ASSERT(cmp != 0);
*out = BigInteger(0);
return false;
}
const BigInteger *a, *b; // Makes a > b const BigInteger *a, *b; // Makes a > b
bool ret; bool ret;
if (cmp < 0) { a = &rhs; b = this; ret = true; } if (cmp < 0) { a = &rhs; b = this; ret = true; }
...@@ -239,7 +240,7 @@ private: ...@@ -239,7 +240,7 @@ private:
uint64_t r = 0; uint64_t r = 0;
for (const char* p = begin; p != end; ++p) { for (const char* p = begin; p != end; ++p) {
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
r = r * 10 + (*p - '0'); r = r * 10u + static_cast<unsigned>(*p - '0');
} }
return r; return r;
} }
...@@ -252,9 +253,10 @@ private: ...@@ -252,9 +253,10 @@ private:
(*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__)
unsigned __int128 p = static_cast<unsigned __int128>(a) * static_cast<unsigned __int128>(b); __extension__ typedef unsigned __int128 uint128;
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
p += k; p += k;
*outHigh = 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;
...@@ -274,12 +276,6 @@ private: ...@@ -274,12 +276,6 @@ private:
#endif #endif
} }
static Type FullAdd(Type a, Type b, bool inCarry, bool* outCarry) {
Type c = a + b + (inCarry ? 1 : 0);
*outCarry = c < a;
return c;
}
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;
......
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_CLZLL_H_
#define RAPIDJSON_CLZLL_H_
#include "../rapidjson.h"
#if defined(_MSC_VER) && !defined(UNDER_CE)
#include <intrin.h>
#if defined(_WIN64)
#pragma intrinsic(_BitScanReverse64)
#else
#pragma intrinsic(_BitScanReverse)
#endif
#endif
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
inline uint32_t clzll(uint64_t x) {
// Passing 0 to __builtin_clzll is UB in GCC and results in an
// infinite loop in the software implementation.
RAPIDJSON_ASSERT(x != 0);
#if defined(_MSC_VER) && !defined(UNDER_CE)
unsigned long r = 0;
#if defined(_WIN64)
_BitScanReverse64(&r, x);
#else
// Scan the high 32 bits.
if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
return 63 - (r + 32);
// Scan the low 32 bits.
_BitScanReverse(&r, static_cast<uint32_t>(x & 0xFFFFFFFF));
#endif // _WIN64
return 63 - r;
#elif (defined(__GNUC__) && __GNUC__ >= 4) || RAPIDJSON_HAS_BUILTIN(__builtin_clzll)
// __builtin_clzll wrapper
return static_cast<uint32_t>(__builtin_clzll(x));
#else
// naive version
uint32_t r = 0;
while (!(x & (static_cast<uint64_t>(1) << 63))) {
x <<= 1;
++r;
}
return r;
#endif // _MSC_VER
}
#define RAPIDJSON_CLZLL RAPIDJSON_NAMESPACE::internal::clzll
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_CLZLL_H_
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // Licensed under the MIT License (the "License"); you may not use this file except
// all copies or substantial portions of the Software. // in compliance with the License. You may obtain a copy of the License at
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // http://opensource.org/licenses/MIT
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // Unless required by applicable law or agreed to in writing, software distributed
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // specific language governing permissions and limitations under the License.
// THE SOFTWARE.
// 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:
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
...@@ -25,11 +19,13 @@ ...@@ -25,11 +19,13 @@
#ifndef RAPIDJSON_DIYFP_H_ #ifndef RAPIDJSON_DIYFP_H_
#define RAPIDJSON_DIYFP_H_ #define RAPIDJSON_DIYFP_H_
#if defined(_MSC_VER) #include "../rapidjson.h"
#include "clzll.h"
#include <limits>
#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER)
#include <intrin.h> #include <intrin.h>
#if defined(_M_AMD64) #pragma intrinsic(_umul128)
#pragma intrinsic(_BitScanReverse64)
#endif
#endif #endif
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
...@@ -40,8 +36,13 @@ RAPIDJSON_DIAG_PUSH ...@@ -40,8 +36,13 @@ RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(effc++)
#endif #endif
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
#endif
struct DiyFp { struct DiyFp {
DiyFp() {} DiyFp() : f(), e() {}
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
...@@ -51,12 +52,12 @@ struct DiyFp { ...@@ -51,12 +52,12 @@ struct DiyFp {
uint64_t u64; uint64_t u64;
} u = { d }; } u = { d };
int biased_e = (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 { else {
f = significand; f = significand;
e = kDpMinExponent + 1; e = kDpMinExponent + 1;
...@@ -75,8 +76,9 @@ struct DiyFp { ...@@ -75,8 +76,9 @@ struct DiyFp {
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__)
unsigned __int128 p = static_cast<unsigned __int128>(f) * static_cast<unsigned __int128>(rhs.f); __extension__ typedef unsigned __int128 uint128;
uint64_t h = p >> 64; uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
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++;
...@@ -98,21 +100,8 @@ struct DiyFp { ...@@ -98,21 +100,8 @@ struct DiyFp {
} }
DiyFp Normalize() const { DiyFp Normalize() const {
#if defined(_MSC_VER) && defined(_M_AMD64) int s = static_cast<int>(clzll(f));
unsigned long index;
_BitScanReverse64(&index, f);
return DiyFp(f << (63 - index), e - (63 - index));
#elif defined(__GNUC__) && __GNUC__ >= 4
int s = __builtin_clzll(f);
return DiyFp(f << s, e - s); return DiyFp(f << s, e - s);
#else
DiyFp res = *this;
while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
res.f <<= 1;
res.e--;
}
return res;
#endif
} }
DiyFp NormalizeBoundary() const { DiyFp NormalizeBoundary() const {
...@@ -140,25 +129,18 @@ struct DiyFp { ...@@ -140,25 +129,18 @@ struct DiyFp {
double d; double d;
uint64_t u64; uint64_t u64;
}u; }u;
uint64_t significand = f; RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask);
int exponent = e; if (e < kDpDenormalExponent) {
while (significand > kDpHiddenBit + kDpSignificandMask) { // Underflow.
significand >>= 1; return 0.0;
exponent++;
}
while (exponent > kDpDenormalExponent && (significand & kDpHiddenBit) == 0) {
significand <<= 1;
exponent--;
} }
if (exponent >= kDpMaxExponent) { if (e >= kDpMaxExponent) {
u.u64 = kDpExponentMask; // Infinity // Overflow.
return u.d; return std::numeric_limits<double>::infinity();
} }
else if (exponent < kDpDenormalExponent) const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
return 0.0; static_cast<uint64_t>(e + kDpExponentBias);
const uint64_t be = (exponent == kDpDenormalExponent && (significand & kDpHiddenBit) == 0) ? 0 : u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
static_cast<uint64_t>(exponent + kDpExponentBias);
u.u64 = (significand & kDpSignificandMask) | (be << kDpSignificandSize);
return u.d; return u.d;
} }
...@@ -235,15 +217,16 @@ inline DiyFp GetCachedPowerByIndex(size_t index) { ...@@ -235,15 +217,16 @@ inline DiyFp GetCachedPowerByIndex(size_t index) {
641, 667, 694, 720, 747, 774, 800, 827, 853, 880, 641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
907, 933, 960, 986, 1013, 1039, 1066 907, 933, 960, 986, 1013, 1039, 1066
}; };
RAPIDJSON_ASSERT(index < 87);
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
} }
inline DiyFp GetCachedPower(int e, int* K) { inline DiyFp GetCachedPower(int e, int* K) {
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374; //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
int k = static_cast<int>(dk); int k = static_cast<int>(dk);
if (k != dk) if (dk - k > 0.0)
k++; k++;
unsigned index = static_cast<unsigned>((k >> 3) + 1); unsigned index = static_cast<unsigned>((k >> 3) + 1);
...@@ -253,15 +236,21 @@ inline DiyFp GetCachedPower(int e, int* K) { ...@@ -253,15 +236,21 @@ inline DiyFp GetCachedPower(int e, int* K) {
} }
inline DiyFp GetCachedPower10(int exp, int *outExp) { inline DiyFp GetCachedPower10(int exp, int *outExp) {
unsigned index = (exp + 348) / 8; RAPIDJSON_ASSERT(exp >= -348);
*outExp = -348 + index * 8; unsigned index = static_cast<unsigned>(exp + 348) / 8u;
return GetCachedPowerByIndex(index); *outExp = -348 + static_cast<int>(index) * 8;
} return GetCachedPowerByIndex(index);
}
#ifdef __GNUC__ #ifdef __GNUC__
RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_POP
#endif #endif
#ifdef __clang__
RAPIDJSON_DIAG_POP
RAPIDJSON_DIAG_OFF(padded)
#endif
} // namespace internal } // namespace internal
RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_END
......
// Copyright (C) 2011 Milo Yip // 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.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// 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:
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
...@@ -27,6 +21,7 @@ ...@@ -27,6 +21,7 @@
#include "itoa.h" // GetDigitsLut() #include "itoa.h" // GetDigitsLut()
#include "diyfp.h" #include "diyfp.h"
#include "ieee754.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
...@@ -34,6 +29,7 @@ namespace internal { ...@@ -34,6 +29,7 @@ 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
#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) {
...@@ -45,7 +41,7 @@ inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uin ...@@ -45,7 +41,7 @@ inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uin
} }
} }
inline unsigned 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;
...@@ -55,8 +51,10 @@ inline unsigned CountDecimalDigit32(uint32_t n) { ...@@ -55,8 +51,10 @@ inline unsigned CountDecimalDigit32(uint32_t n) {
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;
if (n < 1000000000) return 9; // Will not reach 10 digits in DigitGen()
return 10; //if (n < 1000000000) return 9;
//return 10;
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) {
...@@ -65,13 +63,12 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff ...@@ -65,13 +63,12 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
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); int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
*len = 0; *len = 0;
while (kappa > 0) { while (kappa > 0) {
uint32_t d; uint32_t d = 0;
switch (kappa) { switch (kappa) {
case 10: d = p1 / 1000000000; p1 %= 1000000000; break;
case 9: d = p1 / 100000000; p1 %= 100000000; break; case 9: d = p1 / 100000000; p1 %= 100000000; break;
case 8: d = p1 / 10000000; p1 %= 10000000; break; case 8: d = p1 / 10000000; p1 %= 10000000; break;
case 7: d = p1 / 1000000; p1 %= 1000000; break; case 7: d = p1 / 1000000; p1 %= 1000000; break;
...@@ -81,14 +78,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff ...@@ -81,14 +78,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
case 3: d = p1 / 100; p1 %= 100; break; case 3: d = p1 / 100; p1 %= 100; break;
case 2: d = p1 / 10; p1 %= 10; break; case 2: d = p1 / 10; p1 %= 10; break;
case 1: d = p1; p1 = 0; break; case 1: d = p1; p1 = 0; break;
default: default:;
#if defined(_MSC_VER)
__assume(0);
#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
__builtin_unreachable();
#else
d = 0;
#endif
} }
if (d || *len) if (d || *len)
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d)); buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
...@@ -112,7 +102,8 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff ...@@ -112,7 +102,8 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff
kappa--; kappa--;
if (p2 < delta) { if (p2 < delta) {
*K += kappa; *K += kappa;
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]); int index = -kappa;
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0));
return; return;
} }
} }
...@@ -156,10 +147,10 @@ inline char* WriteExponent(int K, char* buffer) { ...@@ -156,10 +147,10 @@ inline char* WriteExponent(int K, char* buffer) {
return buffer; return buffer;
} }
inline char* Prettify(char* buffer, int length, int k) { inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
const int kk = length + k; // 10^(kk-1) <= v < 10^kk const int kk = length + k; // 10^(kk-1) <= v < 10^kk
if (length <= kk && kk <= 21) { if (0 <= k && kk <= 21) {
// 1234e7 -> 12340000000 // 1234e7 -> 12340000000
for (int i = length; i < kk; i++) for (int i = length; i < kk; i++)
buffer[i] = '0'; buffer[i] = '0';
...@@ -169,19 +160,44 @@ inline char* Prettify(char* buffer, int length, int k) { ...@@ -169,19 +160,44 @@ inline char* Prettify(char* buffer, int length, int k) {
} }
else if (0 < kk && kk <= 21) { else if (0 < kk && kk <= 21) {
// 1234e-2 -> 12.34 // 1234e-2 -> 12.34
std::memmove(&buffer[kk + 1], &buffer[kk], length - kk); std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
buffer[kk] = '.'; buffer[kk] = '.';
return &buffer[length + 1]; 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) { else if (-6 < kk && kk <= 0) {
// 1234e-6 -> 0.001234 // 1234e-6 -> 0.001234
const int offset = 2 - kk; const int offset = 2 - kk;
std::memmove(&buffer[offset], &buffer[0], length); std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
buffer[0] = '0'; buffer[0] = '0';
buffer[1] = '.'; buffer[1] = '.';
for (int i = 2; i < offset; i++) for (int i = 2; i < offset; i++)
buffer[i] = '0'; buffer[i] = '0';
return &buffer[length + offset]; 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) { else if (length == 1) {
// 1e30 // 1e30
...@@ -190,15 +206,19 @@ inline char* Prettify(char* buffer, int length, int k) { ...@@ -190,15 +206,19 @@ inline char* Prettify(char* buffer, int length, int k) {
} }
else { else {
// 1234e30 -> 1.234e33 // 1234e30 -> 1.234e33
std::memmove(&buffer[2], &buffer[1], length - 1); std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
buffer[1] = '.'; buffer[1] = '.';
buffer[length + 1] = 'e'; buffer[length + 1] = 'e';
return WriteExponent(kk - 1, &buffer[0 + length + 2]); return WriteExponent(kk - 1, &buffer[0 + length + 2]);
} }
} }
inline char* dtoa(double value, char* buffer) { inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
if (value == 0) { RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
Double d(value);
if (d.IsZero()) {
if (d.Sign())
*buffer++ = '-'; // -0.0, Issue #289
buffer[0] = '0'; buffer[0] = '0';
buffer[1] = '.'; buffer[1] = '.';
buffer[2] = '0'; buffer[2] = '0';
...@@ -211,7 +231,7 @@ inline char* dtoa(double value, char* buffer) { ...@@ -211,7 +231,7 @@ inline char* dtoa(double value, char* buffer) {
} }
int length, K; int length, K;
Grisu2(value, buffer, &length, &K); Grisu2(value, buffer, &length, &K);
return Prettify(buffer, length, K); return Prettify(buffer, length, K, maxDecimalPlaces);
} }
} }
......
// Copyright (C) 2011 Milo Yip // 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.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_IEEE754_ #ifndef RAPIDJSON_IEEE754_
#define RAPIDJSON_IEEE754_ #define RAPIDJSON_IEEE754_
...@@ -29,38 +23,32 @@ namespace internal { ...@@ -29,38 +23,32 @@ 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();
} }
double PreviousPositiveDouble() const { bool Sign() const { return (u_ & kSignMask) != 0; }
RAPIDJSON_ASSERT(!Sign()); uint64_t Significand() const { return u_ & kSignificandMask; }
if (d == 0.0) int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
return 0.0;
else
return Double(u - 1).Value();
}
bool Sign() const { return (u & kSignMask) != 0; }
uint64_t Significand() const { return u & kSignificandMask; }
int Exponent() const { return ((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 IsNormal() const { return (u & kExponentMask) != 0 || Significand() == 0; } bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 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 unsigned 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)
...@@ -79,8 +67,8 @@ private: ...@@ -79,8 +67,8 @@ private:
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_;
}; };
}; };
......
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // Licensed under the MIT License (the "License"); you may not use this file except
// all copies or substantial portions of the Software. // in compliance with the License. You may obtain a copy of the License at
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // http://opensource.org/licenses/MIT
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // Unless required by applicable law or agreed to in writing, software distributed
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // specific language governing permissions and limitations under the License.
// THE SOFTWARE.
#ifndef RAPIDJSON_ITOA_ #ifndef RAPIDJSON_ITOA_
#define RAPIDJSON_ITOA_ #define RAPIDJSON_ITOA_
#include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
...@@ -41,12 +37,14 @@ inline const char* GetDigitsLut() { ...@@ -41,12 +37,14 @@ inline const char* GetDigitsLut() {
} }
inline char* u32toa(uint32_t value, char* buffer) { inline char* u32toa(uint32_t value, char* buffer) {
RAPIDJSON_ASSERT(buffer != 0);
const char* cDigitsLut = GetDigitsLut(); const char* cDigitsLut = GetDigitsLut();
if (value < 10000) { if (value < 10000) {
const uint32_t d1 = (value / 100) << 1; const uint32_t d1 = (value / 100) << 1;
const uint32_t d2 = (value % 100) << 1; const uint32_t d2 = (value % 100) << 1;
if (value >= 1000) if (value >= 1000)
*buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1];
if (value >= 100) if (value >= 100)
...@@ -59,13 +57,13 @@ inline char* u32toa(uint32_t value, char* buffer) { ...@@ -59,13 +57,13 @@ inline char* u32toa(uint32_t value, char* buffer) {
// value = bbbbcccc // value = bbbbcccc
const uint32_t b = value / 10000; const uint32_t b = value / 10000;
const uint32_t c = value % 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;
const uint32_t d3 = (c / 100) << 1; const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1; const uint32_t d4 = (c % 100) << 1;
if (value >= 10000000) if (value >= 10000000)
*buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1];
if (value >= 1000000) if (value >= 1000000)
...@@ -73,7 +71,7 @@ inline char* u32toa(uint32_t value, char* buffer) { ...@@ -73,7 +71,7 @@ inline char* u32toa(uint32_t value, char* buffer) {
if (value >= 100000) if (value >= 100000)
*buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4];
...@@ -81,10 +79,10 @@ inline char* u32toa(uint32_t value, char* buffer) { ...@@ -81,10 +79,10 @@ inline char* u32toa(uint32_t value, char* buffer) {
} }
else { else {
// value = aabbbbcccc in decimal // value = aabbbbcccc in decimal
const uint32_t a = value / 100000000; // 1 to 42 const uint32_t a = value / 100000000; // 1 to 42
value %= 100000000; value %= 100000000;
if (a >= 10) { if (a >= 10) {
const unsigned i = a << 1; const unsigned i = a << 1;
*buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i];
...@@ -95,13 +93,13 @@ inline char* u32toa(uint32_t value, char* buffer) { ...@@ -95,13 +93,13 @@ inline char* u32toa(uint32_t value, char* buffer) {
const uint32_t b = value / 10000; // 0 to 9999 const uint32_t b = value / 10000; // 0 to 9999
const uint32_t c = value % 10000; // 0 to 9999 const uint32_t c = value % 10000; // 0 to 9999
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;
const uint32_t d3 = (c / 100) << 1; const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1; const uint32_t d4 = (c % 100) << 1;
*buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2];
...@@ -115,15 +113,18 @@ inline char* u32toa(uint32_t value, char* buffer) { ...@@ -115,15 +113,18 @@ inline char* u32toa(uint32_t value, char* buffer) {
} }
inline char* i32toa(int32_t value, char* buffer) { inline char* i32toa(int32_t value, char* buffer) {
RAPIDJSON_ASSERT(buffer != 0);
uint32_t u = static_cast<uint32_t>(value);
if (value < 0) { if (value < 0) {
*buffer++ = '-'; *buffer++ = '-';
value = -value; u = ~u + 1;
} }
return u32toa(static_cast<uint32_t>(value), buffer); return u32toa(u, buffer);
} }
inline char* u64toa(uint64_t value, char* buffer) { inline char* u64toa(uint64_t value, char* buffer) {
RAPIDJSON_ASSERT(buffer != 0);
const char* cDigitsLut = GetDigitsLut(); const char* cDigitsLut = GetDigitsLut();
const uint64_t kTen8 = 100000000; const uint64_t kTen8 = 100000000;
const uint64_t kTen9 = kTen8 * 10; const uint64_t kTen9 = kTen8 * 10;
...@@ -134,13 +135,13 @@ inline char* u64toa(uint64_t value, char* buffer) { ...@@ -134,13 +135,13 @@ inline char* u64toa(uint64_t value, char* buffer) {
const uint64_t kTen14 = kTen8 * 1000000; const uint64_t kTen14 = kTen8 * 1000000;
const uint64_t kTen15 = kTen8 * 10000000; const uint64_t kTen15 = kTen8 * 10000000;
const uint64_t kTen16 = kTen8 * kTen8; const uint64_t kTen16 = kTen8 * kTen8;
if (value < kTen8) { if (value < kTen8) {
uint32_t v = static_cast<uint32_t>(value); uint32_t v = static_cast<uint32_t>(value);
if (v < 10000) { if (v < 10000) {
const uint32_t d1 = (v / 100) << 1; const uint32_t d1 = (v / 100) << 1;
const uint32_t d2 = (v % 100) << 1; const uint32_t d2 = (v % 100) << 1;
if (v >= 1000) if (v >= 1000)
*buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1];
if (v >= 100) if (v >= 100)
...@@ -153,13 +154,13 @@ inline char* u64toa(uint64_t value, char* buffer) { ...@@ -153,13 +154,13 @@ inline char* u64toa(uint64_t value, char* buffer) {
// value = bbbbcccc // value = bbbbcccc
const uint32_t b = v / 10000; const uint32_t b = v / 10000;
const uint32_t c = v % 10000; const uint32_t c = v % 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;
const uint32_t d3 = (c / 100) << 1; const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1; const uint32_t d4 = (c % 100) << 1;
if (value >= 10000000) if (value >= 10000000)
*buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1];
if (value >= 1000000) if (value >= 1000000)
...@@ -167,7 +168,7 @@ inline char* u64toa(uint64_t value, char* buffer) { ...@@ -167,7 +168,7 @@ inline char* u64toa(uint64_t value, char* buffer) {
if (value >= 100000) if (value >= 100000)
*buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4];
...@@ -177,22 +178,22 @@ inline char* u64toa(uint64_t value, char* buffer) { ...@@ -177,22 +178,22 @@ inline char* u64toa(uint64_t value, char* buffer) {
else if (value < kTen16) { else if (value < kTen16) {
const uint32_t v0 = static_cast<uint32_t>(value / kTen8); const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = 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 b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000; const uint32_t c0 = v0 % 10000;
const uint32_t d1 = (b0 / 100) << 1; const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1; const uint32_t d2 = (b0 % 100) << 1;
const uint32_t d3 = (c0 / 100) << 1; const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1; const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000; const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000; const uint32_t c1 = v1 % 10000;
const uint32_t d5 = (b1 / 100) << 1; const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1; const uint32_t d6 = (b1 % 100) << 1;
const uint32_t d7 = (c1 / 100) << 1; const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1; const uint32_t d8 = (c1 % 100) << 1;
...@@ -210,9 +211,8 @@ inline char* u64toa(uint64_t value, char* buffer) { ...@@ -210,9 +211,8 @@ inline char* u64toa(uint64_t value, char* buffer) {
*buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d3 + 1];
if (value >= kTen9) if (value >= kTen9)
*buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4];
if (value >= kTen8)
*buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d4 + 1];
*buffer++ = cDigitsLut[d5]; *buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1]; *buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6]; *buffer++ = cDigitsLut[d6];
...@@ -225,7 +225,7 @@ inline char* u64toa(uint64_t value, char* buffer) { ...@@ -225,7 +225,7 @@ inline char* u64toa(uint64_t value, char* buffer) {
else { else {
const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844 const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
value %= kTen16; value %= kTen16;
if (a < 10) if (a < 10)
*buffer++ = static_cast<char>('0' + static_cast<char>(a)); *buffer++ = static_cast<char>('0' + static_cast<char>(a));
else if (a < 100) { else if (a < 100) {
...@@ -235,7 +235,7 @@ inline char* u64toa(uint64_t value, char* buffer) { ...@@ -235,7 +235,7 @@ inline char* u64toa(uint64_t value, char* buffer) {
} }
else if (a < 1000) { else if (a < 1000) {
*buffer++ = static_cast<char>('0' + static_cast<char>(a / 100)); *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
const uint32_t i = (a % 100) << 1; const uint32_t i = (a % 100) << 1;
*buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1]; *buffer++ = cDigitsLut[i + 1];
...@@ -248,28 +248,28 @@ inline char* u64toa(uint64_t value, char* buffer) { ...@@ -248,28 +248,28 @@ inline char* u64toa(uint64_t value, char* buffer) {
*buffer++ = cDigitsLut[j]; *buffer++ = cDigitsLut[j];
*buffer++ = cDigitsLut[j + 1]; *buffer++ = cDigitsLut[j + 1];
} }
const uint32_t v0 = static_cast<uint32_t>(value / kTen8); const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = 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 b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000; const uint32_t c0 = v0 % 10000;
const uint32_t d1 = (b0 / 100) << 1; const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1; const uint32_t d2 = (b0 % 100) << 1;
const uint32_t d3 = (c0 / 100) << 1; const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1; const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000; const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000; const uint32_t c1 = v1 % 10000;
const uint32_t d5 = (b1 / 100) << 1; const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1; const uint32_t d6 = (b1 % 100) << 1;
const uint32_t d7 = (c1 / 100) << 1; const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1; const uint32_t d8 = (c1 % 100) << 1;
*buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2];
...@@ -287,17 +287,19 @@ inline char* u64toa(uint64_t value, char* buffer) { ...@@ -287,17 +287,19 @@ inline char* u64toa(uint64_t value, char* buffer) {
*buffer++ = cDigitsLut[d8]; *buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1]; *buffer++ = cDigitsLut[d8 + 1];
} }
return buffer; return buffer;
} }
inline char* i64toa(int64_t value, char* buffer) { inline char* i64toa(int64_t value, char* buffer) {
RAPIDJSON_ASSERT(buffer != 0);
uint64_t u = static_cast<uint64_t>(value);
if (value < 0) { if (value < 0) {
*buffer++ = '-'; *buffer++ = '-';
value = -value; u = ~u + 1;
} }
return u64toa(static_cast<uint64_t>(value), buffer); return u64toa(u, buffer);
} }
} // namespace internal } // namespace internal
......
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// of this software and associated documentation files (the "Software"), to deal //
// in the Software without restriction, including without limitation the rights // Licensed under the MIT License (the "License"); you may not use this file except
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // in compliance with the License. You may obtain a copy of the License at
// copies of the Software, and to permit persons to whom the Software is //
// furnished to do so, subject to the following conditions: // http://opensource.org/licenses/MIT
// //
// The above copyright notice and this permission notice shall be included in // Unless required by applicable law or agreed to in writing, software distributed
// all copies or substantial portions of the Software. // 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
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // specific language governing permissions and limitations under the License.
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #ifndef RAPIDJSON_INTERNAL_META_H_
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #define RAPIDJSON_INTERNAL_META_H_
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN #include "../rapidjson.h"
// THE SOFTWARE.
#ifdef __GNUC__
#ifndef RAPIDJSON_INTERNAL_META_H_ RAPIDJSON_DIAG_PUSH
#define RAPIDJSON_INTERNAL_META_H_ RAPIDJSON_DIAG_OFF(effc++)
#endif
#ifndef RAPIDJSON_RAPIDJSON_H_
#error <rapidjson.h> not yet included. Do not include this file directly. #if defined(_MSC_VER) && !defined(__clang__)
#endif RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(6334)
#ifdef __GNUC__ #endif
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++) #if RAPIDJSON_HAS_CXX11_TYPETRAITS
#endif #include <type_traits>
#if defined(_MSC_VER) #endif
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(6334) //@cond RAPIDJSON_INTERNAL
#endif RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
#include <type_traits> // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
#endif template <typename T> struct Void { typedef void Type; };
//@cond RAPIDJSON_INTERNAL ///////////////////////////////////////////////////////////////////////////////
RAPIDJSON_NAMESPACE_BEGIN // BoolType, TrueType, FalseType
namespace internal { //
template <bool Cond> struct BoolType {
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching static const bool Value = Cond;
template <typename T> struct Void { typedef void Type; }; typedef BoolType Type;
};
/////////////////////////////////////////////////////////////////////////////// typedef BoolType<true> TrueType;
// BoolType, TrueType, FalseType typedef BoolType<false> FalseType;
//
template <bool Cond> struct BoolType {
static const bool Value = Cond; ///////////////////////////////////////////////////////////////////////////////
typedef BoolType Type; // SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
}; //
typedef BoolType<true> TrueType;
typedef BoolType<false> FalseType; template <bool C> struct SelectIfImpl { template <typename T1, typename 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> {};
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
// template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
template <> struct AndExprCond<true, true> : TrueType {};
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; }; template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; }; template <> struct OrExprCond<false, false> : FalseType {};
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 <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {}; template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
template <> struct AndExprCond<true, true> : TrueType {}; template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
template <> struct OrExprCond<false, false> : FalseType {};
///////////////////////////////////////////////////////////////////////////////
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {}; // AddConst, MaybeAddConst, RemoveConst
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {}; template <typename T> struct AddConst { typedef const T Type; };
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {}; template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {}; template <typename T> struct RemoveConst { typedef T Type; };
template <typename T> struct RemoveConst<const T> { typedef T Type; };
///////////////////////////////////////////////////////////////////////////////
// AddConst, MaybeAddConst, RemoveConst ///////////////////////////////////////////////////////////////////////////////
template <typename T> struct AddConst { typedef const T Type; }; // IsSame, IsConst, IsMoreConst, IsPointer
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {}; //
template <typename T> struct RemoveConst { typedef T Type; }; template <typename T, typename U> struct IsSame : FalseType {};
template <typename T> struct RemoveConst<const T> { typedef T Type; }; template <typename T> struct IsSame<T, T> : TrueType {};
template <typename T> struct IsConst : FalseType {};
/////////////////////////////////////////////////////////////////////////////// template <typename T> struct IsConst<const T> : TrueType {};
// IsSame, IsConst, IsMoreConst, IsPointer
// template <typename CT, typename T>
template <typename T, typename U> struct IsSame : FalseType {}; struct IsMoreConst
template <typename T> struct IsSame<T, T> : TrueType {}; : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
template <typename T> struct IsConst : FalseType {};
template <typename T> struct IsConst<const T> : TrueType {}; template <typename T> struct IsPointer : FalseType {};
template <typename T> struct IsPointer<T*> : TrueType {};
template <typename CT, typename T>
struct IsMoreConst ///////////////////////////////////////////////////////////////////////////////
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>, // IsBaseOf
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {}; //
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
template <typename T> struct IsPointer : FalseType {};
template <typename T> struct IsPointer<T*> : TrueType {}; template <typename B, typename D> struct IsBaseOf
: BoolType< ::std::is_base_of<B,D>::value> {};
///////////////////////////////////////////////////////////////////////////////
// IsBaseOf #else // simplified version adopted from Boost
//
#if RAPIDJSON_HAS_CXX11_TYPETRAITS template<typename B, typename D> struct IsBaseOfImpl {
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
template <typename B, typename D> struct IsBaseOf RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
: BoolType< ::std::is_base_of<B,D>::value> {};
typedef char (&Yes)[1];
#else // simplified version adopted from Boost typedef char (&No) [2];
template<typename B, typename D> struct IsBaseOfImpl { template <typename T>
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); static Yes Check(const D*, T);
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); static No Check(const B*, int);
typedef char (&Yes)[1]; struct Host {
typedef char (&No) [2]; operator const B*() const;
operator const D*();
template <typename T> };
static Yes Check(const D*, T);
static No Check(const B*, int); enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
};
struct Host {
operator const B*() const; template <typename B, typename D> struct IsBaseOf
operator const D*(); : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
};
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
};
//////////////////////////////////////////////////////////////////////////
template <typename B, typename D> struct IsBaseOf // EnableIf / DisableIf
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {}; //
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS template <typename T> struct EnableIfCond<false, T> { /* empty */ };
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
////////////////////////////////////////////////////////////////////////// template <typename T> struct DisableIfCond<true, T> { /* empty */ };
// EnableIf / DisableIf
// template <typename Condition, typename T = void>
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; }; struct EnableIf : EnableIfCond<Condition::Value, T> {};
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
template <typename Condition, typename T = void>
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; }; struct DisableIf : DisableIfCond<Condition::Value, T> {};
template <typename T> struct DisableIfCond<true, T> { /* empty */ };
// SFINAE helpers
template <typename Condition, typename T = void> struct SfinaeTag {};
struct EnableIf : EnableIfCond<Condition::Value, T> {}; template <typename T> struct RemoveSfinaeTag;
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
template <typename Condition, typename T = void>
struct DisableIf : DisableIfCond<Condition::Value, T> {}; #define RAPIDJSON_REMOVEFPTR_(type) \
typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
// SFINAE helpers < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
struct SfinaeTag {};
template <typename T> struct RemoveSfinaeTag; #define RAPIDJSON_ENABLEIF(cond) \
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; }; typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_REMOVEFPTR_(type) \
typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ #define RAPIDJSON_DISABLEIF(cond) \
< ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_ENABLEIF(cond) \
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ #define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
<RAPIDJSON_REMOVEFPTR_(cond), \
#define RAPIDJSON_DISABLEIF(cond) \ RAPIDJSON_REMOVEFPTR_(returntype)>::Type
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ <RAPIDJSON_REMOVEFPTR_(cond), \
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ RAPIDJSON_REMOVEFPTR_(returntype)>::Type
<RAPIDJSON_REMOVEFPTR_(cond), \
RAPIDJSON_REMOVEFPTR_(returntype)>::Type } // namespace internal
RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ //@endcond
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
<RAPIDJSON_REMOVEFPTR_(cond), \ #if defined(_MSC_VER) && !defined(__clang__)
RAPIDJSON_REMOVEFPTR_(returntype)>::Type RAPIDJSON_DIAG_POP
#endif
} // namespace internal
RAPIDJSON_NAMESPACE_END #ifdef __GNUC__
//@endcond RAPIDJSON_DIAG_POP
#endif
#if defined(__GNUC__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP #endif // RAPIDJSON_INTERNAL_META_H_
#endif
#endif // RAPIDJSON_INTERNAL_META_H_
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// of this software and associated documentation files (the "Software"), to deal //
// in the Software without restriction, including without limitation the rights // Licensed under the MIT License (the "License"); you may not use this file except
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // in compliance with the License. You may obtain a copy of the License at
// copies of the Software, and to permit persons to whom the Software is //
// furnished to do so, subject to the following conditions: // http://opensource.org/licenses/MIT
// //
// The above copyright notice and this permission notice shall be included in // Unless required by applicable law or agreed to in writing, software distributed
// all copies or substantial portions of the Software. // 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
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // specific language governing permissions and limitations under the License.
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #ifndef RAPIDJSON_POW10_
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #define RAPIDJSON_POW10_
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN #include "../rapidjson.h"
// THE SOFTWARE.
RAPIDJSON_NAMESPACE_BEGIN
#ifndef RAPIDJSON_POW10_ namespace internal {
#define RAPIDJSON_POW10_
//! Computes integer powers of 10 in double (10.0^n).
RAPIDJSON_NAMESPACE_BEGIN /*! This function uses lookup table for fast and accurate results.
namespace internal { \param n non-negative exponent. Must <= 308.
\return 10.0^n
//! Computes integer powers of 10 in double (10.0^n). */
/*! This function uses lookup table for fast and accurate results. inline double Pow10(int n) {
\param n non-negative exponent. Must <= 308. static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
\return 10.0^n 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,
inline double Pow10(int n) { 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,
static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes 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+0, 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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+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+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
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, RAPIDJSON_ASSERT(n >= 0 && n <= 308);
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, return e[n];
1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 }
};
RAPIDJSON_ASSERT(n >= 0 && n <= 308); } // namespace internal
return e[n]; RAPIDJSON_NAMESPACE_END
}
#endif // RAPIDJSON_POW10_
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_POW10_
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_REGEX_H_
#define RAPIDJSON_INTERNAL_REGEX_H_
#include "../allocators.h"
#include "../stream.h"
#include "stack.h"
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
RAPIDJSON_DIAG_OFF(switch-enum)
#elif defined(_MSC_VER)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
#ifndef RAPIDJSON_REGEX_VERBOSE
#define RAPIDJSON_REGEX_VERBOSE 0
#endif
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
///////////////////////////////////////////////////////////////////////////////
// DecodedStream
template <typename SourceStream, typename Encoding>
class DecodedStream {
public:
DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
unsigned Peek() { return codepoint_; }
unsigned Take() {
unsigned c = codepoint_;
if (c) // No further decoding when '\0'
Decode();
return c;
}
private:
void Decode() {
if (!Encoding::Decode(ss_, &codepoint_))
codepoint_ = 0;
}
SourceStream& ss_;
unsigned codepoint_;
};
///////////////////////////////////////////////////////////////////////////////
// GenericRegex
static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
static const SizeType kRegexInvalidRange = ~SizeType(0);
template <typename Encoding, typename Allocator>
class GenericRegexSearch;
//! Regular expression engine with subset of ECMAscript grammar.
/*!
Supported regular expression syntax:
- \c ab Concatenation
- \c a|b Alternation
- \c a? Zero or one
- \c a* Zero or more
- \c a+ One or more
- \c a{3} Exactly 3 times
- \c a{3,} At least 3 times
- \c a{3,5} 3 to 5 times
- \c (ab) Grouping
- \c ^a At the beginning
- \c a$ At the end
- \c . Any character
- \c [abc] Character classes
- \c [a-c] Character class range
- \c [a-z0-9_] Character class combination
- \c [^abc] Negated character classes
- \c [^a-c] Negated character class range
- \c [\b] Backspace (U+0008)
- \c \\| \\\\ ... Escape characters
- \c \\f Form feed (U+000C)
- \c \\n Line feed (U+000A)
- \c \\r Carriage return (U+000D)
- \c \\t Tab (U+0009)
- \c \\v Vertical tab (U+000B)
\note This is a Thompson NFA engine, implemented with reference to
Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).",
https://swtch.com/~rsc/regexp/regexp1.html
*/
template <typename Encoding, typename Allocator = CrtAllocator>
class GenericRegex {
public:
typedef Encoding EncodingType;
typedef typename Encoding::Ch Ch;
template <typename, typename> friend class GenericRegexSearch;
GenericRegex(const Ch* source, Allocator* allocator = 0) :
ownAllocator_(allocator ? 0 : RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_),
states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
anchorBegin_(), anchorEnd_()
{
GenericStringStream<Encoding> ss(source);
DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss);
Parse(ds);
}
~GenericRegex()
{
RAPIDJSON_DELETE(ownAllocator_);
}
bool IsValid() const {
return root_ != kRegexInvalidState;
}
private:
enum Operator {
kZeroOrOne,
kZeroOrMore,
kOneOrMore,
kConcatenation,
kAlternation,
kLeftParenthesis
};
static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.'
static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
static const unsigned kRangeNegationFlag = 0x80000000;
struct Range {
unsigned start; //
unsigned end;
SizeType next;
};
struct State {
SizeType out; //!< Equals to kInvalid for matching state
SizeType out1; //!< Equals to non-kInvalid for split
SizeType rangeStart;
unsigned codepoint;
};
struct Frag {
Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
SizeType start;
SizeType out; //!< link-list of all output states
SizeType minIndex;
};
State& GetState(SizeType index) {
RAPIDJSON_ASSERT(index < stateCount_);
return states_.template Bottom<State>()[index];
}
const State& GetState(SizeType index) const {
RAPIDJSON_ASSERT(index < stateCount_);
return states_.template Bottom<State>()[index];
}
Range& GetRange(SizeType index) {
RAPIDJSON_ASSERT(index < rangeCount_);
return ranges_.template Bottom<Range>()[index];
}
const Range& GetRange(SizeType index) const {
RAPIDJSON_ASSERT(index < rangeCount_);
return ranges_.template Bottom<Range>()[index];
}
template <typename InputStream>
void Parse(DecodedStream<InputStream, Encoding>& ds) {
Stack<Allocator> operandStack(allocator_, 256); // Frag
Stack<Allocator> operatorStack(allocator_, 256); // Operator
Stack<Allocator> atomCountStack(allocator_, 256); // unsigned (Atom per parenthesis)
*atomCountStack.template Push<unsigned>() = 0;
unsigned codepoint;
while (ds.Peek() != 0) {
switch (codepoint = ds.Take()) {
case '^':
anchorBegin_ = true;
break;
case '$':
anchorEnd_ = true;
break;
case '|':
while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
return;
*operatorStack.template Push<Operator>() = kAlternation;
*atomCountStack.template Top<unsigned>() = 0;
break;
case '(':
*operatorStack.template Push<Operator>() = kLeftParenthesis;
*atomCountStack.template Push<unsigned>() = 0;
break;
case ')':
while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
return;
if (operatorStack.Empty())
return;
operatorStack.template Pop<Operator>(1);
atomCountStack.template Pop<unsigned>(1);
ImplicitConcatenation(atomCountStack, operatorStack);
break;
case '?':
if (!Eval(operandStack, kZeroOrOne))
return;
break;
case '*':
if (!Eval(operandStack, kZeroOrMore))
return;
break;
case '+':
if (!Eval(operandStack, kOneOrMore))
return;
break;
case '{':
{
unsigned n, m;
if (!ParseUnsigned(ds, &n))
return;
if (ds.Peek() == ',') {
ds.Take();
if (ds.Peek() == '}')
m = kInfinityQuantifier;
else if (!ParseUnsigned(ds, &m) || m < n)
return;
}
else
m = n;
if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
return;
ds.Take();
}
break;
case '.':
PushOperand(operandStack, kAnyCharacterClass);
ImplicitConcatenation(atomCountStack, operatorStack);
break;
case '[':
{
SizeType range;
if (!ParseRange(ds, &range))
return;
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
GetState(s).rangeStart = range;
*operandStack.template Push<Frag>() = Frag(s, s, s);
}
ImplicitConcatenation(atomCountStack, operatorStack);
break;
case '\\': // Escape character
if (!CharacterEscape(ds, &codepoint))
return; // Unsupported escape character
// fall through to default
RAPIDJSON_DELIBERATE_FALLTHROUGH;
default: // Pattern character
PushOperand(operandStack, codepoint);
ImplicitConcatenation(atomCountStack, operatorStack);
}
}
while (!operatorStack.Empty())
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
return;
// Link the operand to matching state.
if (operandStack.GetSize() == sizeof(Frag)) {
Frag* e = operandStack.template Pop<Frag>(1);
Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
root_ = e->start;
#if RAPIDJSON_REGEX_VERBOSE
printf("root: %d\n", root_);
for (SizeType i = 0; i < stateCount_ ; i++) {
State& s = GetState(i);
printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
}
printf("\n");
#endif
}
}
SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
State* s = states_.template Push<State>();
s->out = out;
s->out1 = out1;
s->codepoint = codepoint;
s->rangeStart = kRegexInvalidRange;
return stateCount_++;
}
void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
*operandStack.template Push<Frag>() = Frag(s, s, s);
}
void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
if (*atomCountStack.template Top<unsigned>())
*operatorStack.template Push<Operator>() = kConcatenation;
(*atomCountStack.template Top<unsigned>())++;
}
SizeType Append(SizeType l1, SizeType l2) {
SizeType old = l1;
while (GetState(l1).out != kRegexInvalidState)
l1 = GetState(l1).out;
GetState(l1).out = l2;
return old;
}
void Patch(SizeType l, SizeType s) {
for (SizeType next; l != kRegexInvalidState; l = next) {
next = GetState(l).out;
GetState(l).out = s;
}
}
bool Eval(Stack<Allocator>& operandStack, Operator op) {
switch (op) {
case kConcatenation:
RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
{
Frag e2 = *operandStack.template Pop<Frag>(1);
Frag e1 = *operandStack.template Pop<Frag>(1);
Patch(e1.out, e2.start);
*operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
}
return true;
case kAlternation:
if (operandStack.GetSize() >= sizeof(Frag) * 2) {
Frag e2 = *operandStack.template Pop<Frag>(1);
Frag e1 = *operandStack.template Pop<Frag>(1);
SizeType s = NewState(e1.start, e2.start, 0);
*operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
return true;
}
return false;
case kZeroOrOne:
if (operandStack.GetSize() >= sizeof(Frag)) {
Frag e = *operandStack.template Pop<Frag>(1);
SizeType s = NewState(kRegexInvalidState, e.start, 0);
*operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
return true;
}
return false;
case kZeroOrMore:
if (operandStack.GetSize() >= sizeof(Frag)) {
Frag e = *operandStack.template Pop<Frag>(1);
SizeType s = NewState(kRegexInvalidState, e.start, 0);
Patch(e.out, s);
*operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
return true;
}
return false;
case kOneOrMore:
if (operandStack.GetSize() >= sizeof(Frag)) {
Frag e = *operandStack.template Pop<Frag>(1);
SizeType s = NewState(kRegexInvalidState, e.start, 0);
Patch(e.out, s);
*operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
return true;
}
return false;
default:
// syntax error (e.g. unclosed kLeftParenthesis)
return false;
}
}
bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
RAPIDJSON_ASSERT(n <= m);
RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
if (n == 0) {
if (m == 0) // a{0} not support
return false;
else if (m == kInfinityQuantifier)
Eval(operandStack, kZeroOrMore); // a{0,} -> a*
else {
Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
for (unsigned i = 0; i < m - 1; i++)
CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
for (unsigned i = 0; i < m - 1; i++)
Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
}
return true;
}
for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
CloneTopOperand(operandStack);
if (m == kInfinityQuantifier)
Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
else if (m > n) {
CloneTopOperand(operandStack); // a{3,5} -> a a a a
Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
for (unsigned i = n; i < m - 1; i++)
CloneTopOperand(operandStack); // a{3,5} -> a a a a? a?
for (unsigned i = n; i < m; i++)
Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
}
for (unsigned i = 0; i < n - 1; i++)
Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
return true;
}
static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
void CloneTopOperand(Stack<Allocator>& operandStack) {
const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
State* s = states_.template Push<State>(count);
memcpy(s, &GetState(src.minIndex), count * sizeof(State));
for (SizeType j = 0; j < count; j++) {
if (s[j].out != kRegexInvalidState)
s[j].out += count;
if (s[j].out1 != kRegexInvalidState)
s[j].out1 += count;
}
*operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
stateCount_ += count;
}
template <typename InputStream>
bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) {
unsigned r = 0;
if (ds.Peek() < '0' || ds.Peek() > '9')
return false;
while (ds.Peek() >= '0' && ds.Peek() <= '9') {
if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
return false; // overflow
r = r * 10 + (ds.Take() - '0');
}
*u = r;
return true;
}
template <typename InputStream>
bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range) {
bool isBegin = true;
bool negate = false;
int step = 0;
SizeType start = kRegexInvalidRange;
SizeType current = kRegexInvalidRange;
unsigned codepoint;
while ((codepoint = ds.Take()) != 0) {
if (isBegin) {
isBegin = false;
if (codepoint == '^') {
negate = true;
continue;
}
}
switch (codepoint) {
case ']':
if (start == kRegexInvalidRange)
return false; // Error: nothing inside []
if (step == 2) { // Add trailing '-'
SizeType r = NewRange('-');
RAPIDJSON_ASSERT(current != kRegexInvalidRange);
GetRange(current).next = r;
}
if (negate)
GetRange(start).start |= kRangeNegationFlag;
*range = start;
return true;
case '\\':
if (ds.Peek() == 'b') {
ds.Take();
codepoint = 0x0008; // Escape backspace character
}
else if (!CharacterEscape(ds, &codepoint))
return false;
// fall through to default
RAPIDJSON_DELIBERATE_FALLTHROUGH;
default:
switch (step) {
case 1:
if (codepoint == '-') {
step++;
break;
}
// fall through to step 0 for other characters
RAPIDJSON_DELIBERATE_FALLTHROUGH;
case 0:
{
SizeType r = NewRange(codepoint);
if (current != kRegexInvalidRange)
GetRange(current).next = r;
if (start == kRegexInvalidRange)
start = r;
current = r;
}
step = 1;
break;
default:
RAPIDJSON_ASSERT(step == 2);
GetRange(current).end = codepoint;
step = 0;
}
}
}
return false;
}
SizeType NewRange(unsigned codepoint) {
Range* r = ranges_.template Push<Range>();
r->start = r->end = codepoint;
r->next = kRegexInvalidRange;
return rangeCount_++;
}
template <typename InputStream>
bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {
unsigned codepoint;
switch (codepoint = ds.Take()) {
case '^':
case '$':
case '|':
case '(':
case ')':
case '?':
case '*':
case '+':
case '.':
case '[':
case ']':
case '{':
case '}':
case '\\':
*escapedCodepoint = codepoint; return true;
case 'f': *escapedCodepoint = 0x000C; return true;
case 'n': *escapedCodepoint = 0x000A; return true;
case 'r': *escapedCodepoint = 0x000D; return true;
case 't': *escapedCodepoint = 0x0009; return true;
case 'v': *escapedCodepoint = 0x000B; return true;
default:
return false; // Unsupported escape character
}
}
Allocator* ownAllocator_;
Allocator* allocator_;
Stack<Allocator> states_;
Stack<Allocator> ranges_;
SizeType root_;
SizeType stateCount_;
SizeType rangeCount_;
static const unsigned kInfinityQuantifier = ~0u;
// For SearchWithAnchoring()
bool anchorBegin_;
bool anchorEnd_;
};
template <typename RegexType, typename Allocator = CrtAllocator>
class GenericRegexSearch {
public:
typedef typename RegexType::EncodingType Encoding;
typedef typename Encoding::Ch Ch;
GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) :
regex_(regex), allocator_(allocator), ownAllocator_(0),
state0_(allocator, 0), state1_(allocator, 0), stateSet_()
{
RAPIDJSON_ASSERT(regex_.IsValid());
if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)();
stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));
state0_.template Reserve<SizeType>(regex_.stateCount_);
state1_.template Reserve<SizeType>(regex_.stateCount_);
}
~GenericRegexSearch() {
Allocator::Free(stateSet_);
RAPIDJSON_DELETE(ownAllocator_);
}
template <typename InputStream>
bool Match(InputStream& is) {
return SearchWithAnchoring(is, true, true);
}
bool Match(const Ch* s) {
GenericStringStream<Encoding> is(s);
return Match(is);
}
template <typename InputStream>
bool Search(InputStream& is) {
return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
}
bool Search(const Ch* s) {
GenericStringStream<Encoding> is(s);
return Search(is);
}
private:
typedef typename RegexType::State State;
typedef typename RegexType::Range Range;
template <typename InputStream>
bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {
DecodedStream<InputStream, Encoding> ds(is);
state0_.Clear();
Stack<Allocator> *current = &state0_, *next = &state1_;
const size_t stateSetSize = GetStateSetSize();
std::memset(stateSet_, 0, stateSetSize);
bool matched = AddState(*current, regex_.root_);
unsigned codepoint;
while (!current->Empty() && (codepoint = ds.Take()) != 0) {
std::memset(stateSet_, 0, stateSetSize);
next->Clear();
matched = false;
for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
const State& sr = regex_.GetState(*s);
if (sr.codepoint == codepoint ||
sr.codepoint == RegexType::kAnyCharacterClass ||
(sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
{
matched = AddState(*next, sr.out) || matched;
if (!anchorEnd && matched)
return true;
}
if (!anchorBegin)
AddState(*next, regex_.root_);
}
internal::Swap(current, next);
}
return matched;
}
size_t GetStateSetSize() const {
return (regex_.stateCount_ + 31) / 32 * 4;
}
// Return whether the added states is a match state
bool AddState(Stack<Allocator>& l, SizeType index) {
RAPIDJSON_ASSERT(index != kRegexInvalidState);
const State& s = regex_.GetState(index);
if (s.out1 != kRegexInvalidState) { // Split
bool matched = AddState(l, s.out);
return AddState(l, s.out1) || matched;
}
else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) {
stateSet_[index >> 5] |= (1u << (index & 31));
*l.template PushUnsafe<SizeType>() = index;
}
return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
}
bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
while (rangeIndex != kRegexInvalidRange) {
const Range& r = regex_.GetRange(rangeIndex);
if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
return yes;
rangeIndex = r.next;
}
return !yes;
}
const RegexType& regex_;
Allocator* allocator_;
Allocator* ownAllocator_;
Stack<Allocator> state0_;
Stack<Allocator> state1_;
uint32_t* stateSet_;
};
typedef GenericRegex<UTF8<> > Regex;
typedef GenericRegexSearch<Regex> RegexSearch;
} // namespace internal
RAPIDJSON_NAMESPACE_END
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
#if defined(__clang__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_INTERNAL_REGEX_H_
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// of this software and associated documentation files (the "Software"), to deal //
// in the Software without restriction, including without limitation the rights // Licensed under the MIT License (the "License"); you may not use this file except
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // in compliance with the License. You may obtain a copy of the License at
// copies of the Software, and to permit persons to whom the Software is //
// furnished to do so, subject to the following conditions: // http://opensource.org/licenses/MIT
// //
// The above copyright notice and this permission notice shall be included in // Unless required by applicable law or agreed to in writing, software distributed
// all copies or substantial portions of the Software. // 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
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // specific language governing permissions and limitations under the License.
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #ifndef RAPIDJSON_INTERNAL_STACK_H_
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #define RAPIDJSON_INTERNAL_STACK_H_
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN #include "../allocators.h"
// THE SOFTWARE. #include "swap.h"
#include <cstddef>
#ifndef RAPIDJSON_INTERNAL_STACK_H_
#define RAPIDJSON_INTERNAL_STACK_H_ #if defined(__clang__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_DIAG_OFF(c++98-compat)
namespace internal { #endif
/////////////////////////////////////////////////////////////////////////////// RAPIDJSON_NAMESPACE_BEGIN
// Stack namespace internal {
//! A type-unsafe stack for storing different types of data. ///////////////////////////////////////////////////////////////////////////////
/*! \tparam Allocator Allocator for allocating stack memory. // Stack
*/
template <typename Allocator> //! A type-unsafe stack for storing different types of data.
class Stack { /*! \tparam Allocator Allocator for allocating stack memory.
public: */
// Optimization note: Do not allocate memory for stack_ in constructor. template <typename Allocator>
// Do it lazily when first Push() -> Expand() -> Resize(). class Stack {
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { public:
RAPIDJSON_ASSERT(stackCapacity > 0); // Optimization note: Do not allocate memory for stack_ in constructor.
} // 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) {
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS }
Stack(Stack&& rhs)
: allocator_(rhs.allocator_), #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
ownAllocator_(rhs.ownAllocator_), Stack(Stack&& rhs)
stack_(rhs.stack_), : allocator_(rhs.allocator_),
stackTop_(rhs.stackTop_), ownAllocator_(rhs.ownAllocator_),
stackEnd_(rhs.stackEnd_), stack_(rhs.stack_),
initialCapacity_(rhs.initialCapacity_) stackTop_(rhs.stackTop_),
{ stackEnd_(rhs.stackEnd_),
rhs.allocator_ = 0; initialCapacity_(rhs.initialCapacity_)
rhs.ownAllocator_ = 0; {
rhs.stack_ = 0; rhs.allocator_ = 0;
rhs.stackTop_ = 0; rhs.ownAllocator_ = 0;
rhs.stackEnd_ = 0; rhs.stack_ = 0;
rhs.initialCapacity_ = 0; rhs.stackTop_ = 0;
} rhs.stackEnd_ = 0;
#endif rhs.initialCapacity_ = 0;
}
~Stack() { #endif
Destroy();
} ~Stack() {
Destroy();
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS }
Stack& operator=(Stack&& rhs) {
if (&rhs != this) #if RAPIDJSON_HAS_CXX11_RVALUE_REFS
{ Stack& operator=(Stack&& rhs) {
Destroy(); if (&rhs != this)
{
allocator_ = rhs.allocator_; Destroy();
ownAllocator_ = rhs.ownAllocator_;
stack_ = rhs.stack_; allocator_ = rhs.allocator_;
stackTop_ = rhs.stackTop_; ownAllocator_ = rhs.ownAllocator_;
stackEnd_ = rhs.stackEnd_; stack_ = rhs.stack_;
initialCapacity_ = rhs.initialCapacity_; stackTop_ = rhs.stackTop_;
stackEnd_ = rhs.stackEnd_;
rhs.allocator_ = 0; initialCapacity_ = rhs.initialCapacity_;
rhs.ownAllocator_ = 0;
rhs.stack_ = 0; rhs.allocator_ = 0;
rhs.stackTop_ = 0; rhs.ownAllocator_ = 0;
rhs.stackEnd_ = 0; rhs.stack_ = 0;
rhs.initialCapacity_ = 0; rhs.stackTop_ = 0;
} rhs.stackEnd_ = 0;
return *this; rhs.initialCapacity_ = 0;
} }
#endif return *this;
}
void Clear() { stackTop_ = stack_; } #endif
void ShrinkToFit() { void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
if (Empty()) { internal::Swap(allocator_, rhs.allocator_);
// If the stack is empty, completely deallocate the memory. internal::Swap(ownAllocator_, rhs.ownAllocator_);
Allocator::Free(stack_); internal::Swap(stack_, rhs.stack_);
stack_ = 0; internal::Swap(stackTop_, rhs.stackTop_);
stackTop_ = 0; internal::Swap(stackEnd_, rhs.stackEnd_);
stackEnd_ = 0; internal::Swap(initialCapacity_, rhs.initialCapacity_);
} }
else
Resize(GetSize()); void Clear() { stackTop_ = stack_; }
}
void ShrinkToFit() {
// Optimization note: try to minimize the size of this function for force inline. if (Empty()) {
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function. // If the stack is empty, completely deallocate the memory.
template<typename T> Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { stack_ = 0;
// Expand the stack if needed stackTop_ = 0;
if (stackTop_ + sizeof(T) * count >= stackEnd_) stackEnd_ = 0;
Expand<T>(count); }
else
T* ret = reinterpret_cast<T*>(stackTop_); Resize(GetSize());
stackTop_ += sizeof(T) * count; }
return ret;
} // Optimization note: try to minimize the size of this function for force inline.
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
template<typename T> template<typename T>
T* Pop(size_t count) { RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); // Expand the stack if needed
stackTop_ -= count * sizeof(T); if (RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
return reinterpret_cast<T*>(stackTop_); Expand<T>(count);
} }
template<typename T> template<typename T>
T* Top() { RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); Reserve<T>(count);
return reinterpret_cast<T*>(stackTop_ - sizeof(T)); return PushUnsafe<T>(count);
} }
template<typename T> template<typename T>
T* Bottom() { return (T*)stack_; } RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
RAPIDJSON_ASSERT(stackTop_);
Allocator& GetAllocator() { return *allocator_; } RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
bool Empty() const { return stackTop_ == stack_; } T* ret = reinterpret_cast<T*>(stackTop_);
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); } stackTop_ += sizeof(T) * count;
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); } return ret;
}
private:
template<typename T> template<typename T>
void Expand(size_t count) { T* Pop(size_t count) {
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
size_t newCapacity; stackTop_ -= count * sizeof(T);
if (stack_ == 0) { return reinterpret_cast<T*>(stackTop_);
if (!allocator_) }
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
newCapacity = initialCapacity_; template<typename T>
} else { T* Top() {
newCapacity = GetCapacity(); RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
newCapacity += (newCapacity + 1) / 2; return reinterpret_cast<T*>(stackTop_ - sizeof(T));
} }
size_t newSize = GetSize() + sizeof(T) * count;
if (newCapacity < newSize) template<typename T>
newCapacity = newSize; const T* Top() const {
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
Resize(newCapacity); return reinterpret_cast<T*>(stackTop_ - sizeof(T));
} }
void Resize(size_t newCapacity) { template<typename T>
const size_t size = GetSize(); // Backup the current size T* End() { return reinterpret_cast<T*>(stackTop_); }
stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity);
stackTop_ = stack_ + size; template<typename T>
stackEnd_ = stack_ + newCapacity; const T* End() const { return reinterpret_cast<T*>(stackTop_); }
}
template<typename T>
void Destroy() { T* Bottom() { return reinterpret_cast<T*>(stack_); }
Allocator::Free(stack_);
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack template<typename T>
} const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
// Prohibit copy constructor & assignment operator. bool HasAllocator() const {
Stack(const Stack&); return allocator_ != 0;
Stack& operator=(const Stack&); }
Allocator* allocator_; Allocator& GetAllocator() {
Allocator* ownAllocator_; RAPIDJSON_ASSERT(allocator_);
char *stack_; return *allocator_;
char *stackTop_; }
char *stackEnd_;
size_t initialCapacity_; 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_); }
} // namespace internal
RAPIDJSON_NAMESPACE_END private:
template<typename T>
#endif // RAPIDJSON_STACK_H_ 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
RAPIDJSON_NAMESPACE_END
#if defined(__clang__)
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_STACK_H_
// Copyright (C) 2011 Milo Yip // Tencent is pleased to support the open source community by making RapidJSON available.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
// of this software and associated documentation files (the "Software"), to deal //
// in the Software without restriction, including without limitation the rights // Licensed under the MIT License (the "License"); you may not use this file except
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // in compliance with the License. You may obtain a copy of the License at
// copies of the Software, and to permit persons to whom the Software is //
// furnished to do so, subject to the following conditions: // http://opensource.org/licenses/MIT
// //
// The above copyright notice and this permission notice shall be included in // Unless required by applicable law or agreed to in writing, software distributed
// all copies or substantial portions of the Software. // 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
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // specific language governing permissions and limitations under the License.
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #define RAPIDJSON_INTERNAL_STRFUNC_H_
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN #include "../stream.h"
// THE SOFTWARE. #include <cwchar>
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ RAPIDJSON_NAMESPACE_BEGIN
#define RAPIDJSON_INTERNAL_STRFUNC_H_ namespace internal {
RAPIDJSON_NAMESPACE_BEGIN //! Custom strlen() which works on different character types.
namespace internal { /*! \tparam Ch Character type (e.g. char, wchar_t, short)
\param s Null-terminated input string.
//! Custom strlen() which works on different character types. \return Number of characters in the string.
/*! \tparam Ch Character type (e.g. char, wchar_t, short) \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
\param s Null-terminated input string. */
\return Number of characters in the string. template <typename Ch>
\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. inline SizeType StrLen(const Ch* s) {
*/ RAPIDJSON_ASSERT(s != 0);
template <typename Ch> const Ch* p = s;
inline SizeType StrLen(const Ch* s) { while (*p) ++p;
const Ch* p = s; return SizeType(p - s);
while (*p) ++p; }
return SizeType(p - s);
} template <>
inline SizeType StrLen(const char* s) {
} // namespace internal return SizeType(std::strlen(s));
RAPIDJSON_NAMESPACE_END }
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_ template <>
inline SizeType StrLen(const wchar_t* s) {
return SizeType(std::wcslen(s));
}
//! Custom strcmpn() which works on different character types.
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
\param s1 Null-terminated input string.
\param s2 Null-terminated input string.
\return 0 if equal
*/
template<typename Ch>
inline int StrCmp(const Ch* s1, const Ch* s2) {
RAPIDJSON_ASSERT(s1 != 0);
RAPIDJSON_ASSERT(s2 != 0);
while(*s1 && (*s1 == *s2)) { s1++; s2++; }
return static_cast<unsigned>(*s1) < static_cast<unsigned>(*s2) ? -1 : static_cast<unsigned>(*s1) > static_cast<unsigned>(*s2);
}
//! Returns number of code points in a encoded string.
template<typename Encoding>
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
RAPIDJSON_ASSERT(s != 0);
RAPIDJSON_ASSERT(outCount != 0);
GenericStringStream<Encoding> is(s);
const typename Encoding::Ch* end = s + length;
SizeType count = 0;
while (is.src_ < end) {
unsigned codepoint;
if (!Encoding::Decode(is, &codepoint))
return false;
count++;
}
*outCount = count;
return true;
}
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
// Copyright (C) 2011 Milo Yip // 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.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_STRTOD_ #ifndef RAPIDJSON_STRTOD_
#define RAPIDJSON_STRTOD_ #define RAPIDJSON_STRTOD_
#include "../rapidjson.h"
#include "ieee754.h" #include "ieee754.h"
#include "biginteger.h" #include "biginteger.h"
#include "diyfp.h" #include "diyfp.h"
#include "pow10.h" #include "pow10.h"
#include <climits>
#include <limits>
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
namespace internal { namespace internal {
...@@ -58,7 +53,7 @@ inline T Min3(T a, T b, T c) { ...@@ -58,7 +53,7 @@ inline T Min3(T a, T b, T c) {
return m; return m;
} }
inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp, bool* adjustToNegative) { inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
const Double db(b); const Double db(b);
const uint64_t bInt = db.IntegerSignificand(); const uint64_t bInt = db.IntegerSignificand();
const int bExp = db.IntegerExponent(); const int bExp = db.IntegerExponent();
...@@ -101,28 +96,18 @@ inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp, bool* adj ...@@ -101,28 +96,18 @@ inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp, bool* adj
hS_Exp2 -= common_Exp2; hS_Exp2 -= common_Exp2;
BigInteger dS = d; BigInteger dS = d;
dS.MultiplyPow5(dS_Exp5) <<= dS_Exp2; dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
BigInteger bS(bInt); BigInteger bS(bInt);
bS.MultiplyPow5(bS_Exp5) <<= bS_Exp2; bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
BigInteger hS(1); BigInteger hS(1);
hS.MultiplyPow5(hS_Exp5) <<= hS_Exp2; hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
BigInteger delta(0); BigInteger delta(0);
*adjustToNegative = dS.Difference(bS, &delta); dS.Difference(bS, &delta);
int cmp = delta.Compare(hS); return delta.Compare(hS);
// If delta is within 1/2 ULP, check for special case when significand is power of two.
// In this case, need to compare with 1/2h in the lower bound.
if (cmp < 0 && *adjustToNegative && // within and dS < bS
db.IsNormal() && (bInt & (bInt - 1)) == 0 && // Power of 2
db.Uint64Value() != RAPIDJSON_UINT64_C2(0x00100000, 0x00000000)) // minimum normal number must not do this
{
delta <<= 1;
return delta.Compare(hS);
}
return cmp;
} }
inline bool StrtodFast(double d, int p, double* result) { inline bool StrtodFast(double d, int p, double* result) {
...@@ -143,46 +128,46 @@ inline bool StrtodFast(double d, int p, double* result) { ...@@ -143,46 +128,46 @@ inline bool StrtodFast(double d, int p, double* result) {
} }
// Compute an approximation and see if it is within 1/2 ULP // Compute an approximation and see if it is within 1/2 ULP
inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) { inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) {
uint64_t significand = 0; uint64_t significand = 0;
size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
for (; i < length; i++) { for (; i < dLen; i++) {
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
break; break;
significand = significand * 10 + (decimals[i] - '0'); significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
} }
if (i < length && decimals[i] >= '5') // Rounding if (i < dLen && decimals[i] >= '5') // Rounding
significand++; significand++;
size_t remaining = length - i; int remaining = dLen - i;
const unsigned kUlpShift = 3; const int kUlpShift = 3;
const unsigned kUlp = 1 << kUlpShift; const int kUlp = 1 << kUlpShift;
int error = (remaining == 0) ? 0 : kUlp / 2; int64_t error = (remaining == 0) ? 0 : kUlp / 2;
DiyFp v(significand, 0); DiyFp v(significand, 0);
v = v.Normalize(); v = v.Normalize();
error <<= -v.e; error <<= -v.e;
const int dExp = (int)decimalPosition - (int)i + exp; dExp += remaining;
int actualExp; int actualExp;
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
if (actualExp != dExp) { if (actualExp != dExp) {
static const DiyFp kPow10[] = { static const DiyFp kPow10[] = {
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1 DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2 DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3 DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3
DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4 DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4
DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5 DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7
}; };
int adjustment = dExp - actualExp - 1; int adjustment = dExp - actualExp;
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8);
v = v * kPow10[adjustment]; v = v * kPow10[adjustment - 1];
if (length + adjustment > 19) // has more digits than decimal digits in 64-bit if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit
error += kUlp / 2; error += kUlp / 2;
} }
...@@ -194,10 +179,10 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit ...@@ -194,10 +179,10 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
v = v.Normalize(); v = v.Normalize();
error <<= oldExp - v.e; error <<= oldExp - v.e;
const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
unsigned precisionSize = 64 - effectiveSignificandSize; int precisionSize = 64 - effectiveSignificandSize;
if (precisionSize + kUlpShift >= 64) { if (precisionSize + kUlpShift >= 64) {
unsigned scaleExp = (precisionSize + kUlpShift) - 63; int scaleExp = (precisionSize + kUlpShift) - 63;
v.f >>= scaleExp; v.f >>= scaleExp;
v.e += scaleExp; v.e += scaleExp;
error = (error >> scaleExp) + 1 + kUlp; error = (error >> scaleExp) + 1 + kUlp;
...@@ -207,76 +192,96 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit ...@@ -207,76 +192,96 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit
DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
if (precisionBits >= halfWay + error) if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
rounded.f++; rounded.f++;
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
rounded.f >>= 1;
rounded.e++;
}
}
*result = rounded.ToDouble(); *result = rounded.ToDouble();
return halfWay - error >= precisionBits || precisionBits >= halfWay + error; return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
} }
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) {
const BigInteger dInt(decimals, length); RAPIDJSON_ASSERT(dLen >= 0);
const int dExp = (int)decimalPosition - (int)length + exp; const BigInteger dInt(decimals, static_cast<unsigned>(dLen));
Double a(approx); Double a(approx);
for (int i = 0; i < 10; i++) { int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
bool adjustToNegative; if (cmp < 0)
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp, &adjustToNegative); return a.Value(); // within half ULP
if (cmp < 0) else if (cmp == 0) {
return a.Value(); // within half ULP // Round towards even
else if (cmp == 0) { if (a.Significand() & 1)
// Round towards even return a.NextPositiveDouble();
if (a.Significand() & 1) else
return adjustToNegative ? a.PreviousPositiveDouble() : a.NextPositiveDouble(); return a.Value();
else
return a.Value();
}
else // adjustment
a = adjustToNegative ? a.PreviousPositiveDouble() : a.NextPositiveDouble();
} }
else // adjustment
// This should not happen, but in case there is really a bug, break the infinite-loop return a.NextPositiveDouble();
return a.Value();
} }
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { 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(d >= 0.0);
RAPIDJSON_ASSERT(length >= 1); RAPIDJSON_ASSERT(length >= 1);
double result; double result = 0.0;
if (StrtodFast(d, p, &result)) if (StrtodFast(d, p, &result))
return 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 // Trim leading zeros
while (*decimals == '0' && length > 1) { while (dLen > 0 && *decimals == '0') {
length--; dLen--;
decimals++; decimals++;
decimalPosition--;
} }
// Trim trailing zeros // Trim trailing zeros
while (decimals[length - 1] == '0' && length > 1) { while (dLen > 0 && decimals[dLen - 1] == '0') {
length--; dLen--;
decimalPosition--; dExp++;
exp++; }
if (dLen == 0) { // Buffer only contains zeros.
return 0.0;
} }
// Trim right-most digits // Trim right-most digits
const int kMaxDecimalDigit = 780; const int kMaxDecimalDigit = 767 + 1;
if ((int)length > kMaxDecimalDigit) { if (dLen > kMaxDecimalDigit) {
exp += (int(length) - kMaxDecimalDigit); dExp += dLen - kMaxDecimalDigit;
length = kMaxDecimalDigit; dLen = kMaxDecimalDigit;
} }
// If too small, underflow to zero // If too small, underflow to zero.
if (int(length) + exp < -324) // Any x <= 10^-324 is interpreted as zero.
if (dLen + dExp <= -324)
return 0.0; return 0.0;
if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) // 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; return result;
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
return StrtodBigInteger(result, decimals, length, decimalPosition, exp); return StrtodBigInteger(result, decimals, dLen, dExp);
} }
} // namespace internal } // namespace internal
......
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_SWAP_H_
#define RAPIDJSON_INTERNAL_SWAP_H_
#include "../rapidjson.h"
#if defined(__clang__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(c++98-compat)
#endif
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
//! 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.
\note This has the same semantics as std::swap().
*/
template <typename T>
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
T tmp = a;
a = b;
b = tmp;
}
} // namespace internal
RAPIDJSON_NAMESPACE_END
#if defined(__clang__)
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_INTERNAL_SWAP_H_
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// 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
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ISTREAMWRAPPER_H_
#define RAPIDJSON_ISTREAMWRAPPER_H_
#include "stream.h"
#include <iosfwd>
#include <ios>
#ifdef __clang__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(padded)
#elif defined(_MSC_VER)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
/*!
The classes can be wrapped including but not limited to:
- \c std::istringstream
- \c std::stringstream
- \c std::wistringstream
- \c std::wstringstream
- \c std::ifstream
- \c std::fstream
- \c std::wifstream
- \c std::wfstream
\tparam StreamType Class derived from \c std::basic_istream.
*/
template <typename StreamType>
class BasicIStreamWrapper {
public:
typedef typename StreamType::char_type Ch;
//! Constructor.
/*!
\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) {
Read();
}
//! Constructor.
/*!
\param stream stream opened for read.
\param buffer user-supplied buffer.
\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) {
RAPIDJSON_ASSERT(bufferSize >= 4);
Read();
}
Ch Peek() const { return *current_; }
Ch Take() { Ch c = *current_; Read(); return c; }
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
// Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// For encoding detection only.
const Ch* Peek4() const {
return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
}
private:
BasicIStreamWrapper();
BasicIStreamWrapper(const BasicIStreamWrapper&);
BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
void Read() {
if (current_ < bufferLast_)
++current_;
else if (!eof_) {
count_ += readCount_;
readCount_ = bufferSize_;
bufferLast_ = buffer_ + readCount_ - 1;
current_ = buffer_;
if (!stream_.read(buffer_, static_cast<std::streamsize>(bufferSize_))) {
readCount_ = static_cast<size_t>(stream_.gcount());
*(bufferLast_ = buffer_ + readCount_) = '\0';
eof_ = true;
}
}
}
StreamType &stream_;
Ch peekBuffer_[4], *buffer_;
size_t bufferSize_;
Ch *bufferLast_;
Ch *current_;
size_t readCount_;
size_t count_; //!< Number of characters read
bool eof_;
};
typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
#if defined(__clang__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP
#endif
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ISTREAMWRAPPER_H_
// Copyright (C) 2011 Milo Yip // 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.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Licensed under the MIT License (the "License"); you may not use this file except
// of this software and associated documentation files (the "Software"), to deal // in compliance with the License. You may obtain a copy of the License at
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// //
// The above copyright notice and this permission notice shall be included in // http://opensource.org/licenses/MIT
// all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // Unless required by applicable law or agreed to in writing, software distributed
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONDITIONS OF ANY KIND, either express or implied. See the License for the
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // specific language governing permissions and limitations under the License.
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#ifndef RAPIDJSON_MEMORYBUFFER_H_ #ifndef RAPIDJSON_MEMORYBUFFER_H_
#define RAPIDJSON_MEMORYBUFFER_H_ #define RAPIDJSON_MEMORYBUFFER_H_
#include "rapidjson.h" #include "stream.h"
#include "internal/stack.h" #include "internal/stack.h"
RAPIDJSON_NAMESPACE_BEGIN RAPIDJSON_NAMESPACE_BEGIN
......