Commit 609381fc authored by Milo Yip's avatar Milo Yip

Fixed some clang -Weverything warnings.

parent f930d9e2
......@@ -149,6 +149,9 @@ solution "example"
configuration "vs*"
defines { "_CRT_SECURE_NO_WARNINGS" }
configuration "gmake"
buildoptions "-Weverything"
project "condense"
kind "ConsoleApp"
files "../example/condense/*"
......
......@@ -12,7 +12,7 @@ using namespace rapidjson;
class Person {
public:
Person(const std::string& name, unsigned age) : name_(name), age_(age) {}
virtual ~Person() {}
virtual ~Person();
protected:
template <typename Writer>
......@@ -30,6 +30,9 @@ private:
unsigned age_;
};
Person::~Person() {
}
class Education {
public:
Education(const std::string& school, double GPA) : school_(school), GPA_(GPA) {}
......@@ -56,7 +59,7 @@ class Dependent : public Person {
public:
Dependent(const std::string& name, unsigned age, Education* education = 0) : Person(name, age), education_(education) {}
Dependent(const Dependent& rhs) : Person(rhs) { education_ = (rhs.education_ == 0) ? 0 : new Education(*rhs.education_); }
~Dependent() { delete education_; }
virtual ~Dependent();
template <typename Writer>
void Serialize(Writer& writer) const {
......@@ -77,9 +80,14 @@ private:
Education *education_;
};
Dependent::~Dependent() {
delete education_;
}
class Employee : public Person {
public:
Employee(const std::string& name, unsigned age, bool married) : Person(name, age), married_(married) {}
virtual ~Employee();
void AddDependent(const Dependent& dependent) {
dependents_.push_back(dependent);
......@@ -104,10 +112,13 @@ public:
}
private:
bool married_;
std::vector<Dependent> dependents_;
bool married_;
};
Employee::~Employee() {
}
int main(int, char*[]) {
std::vector<Employee> employees;
......
......@@ -23,10 +23,12 @@ int main(int, char*[]) {
return 1;
#else
// In-situ parsing, decode strings directly in the source string. Source must be string.
char buffer[sizeof(json)];
memcpy(buffer, json, sizeof(json));
if (document.ParseInsitu<0>(buffer).HasParseError())
return 1;
{
char buffer[sizeof(json)];
memcpy(buffer, json, sizeof(json));
if (document.ParseInsitu<0>(buffer).HasParseError())
return 1;
}
#endif
printf("\nParsing to document succeeded.\n");
......@@ -128,7 +130,7 @@ int main(int, char*[]) {
char buffer[10];
int len = sprintf(buffer, "%s %s", "Milo", "Yip"); // synthetic example of dynamically created string.
author.SetString(buffer, len, document.GetAllocator());
author.SetString(buffer, static_cast<size_t>(len), document.GetAllocator());
// Shorter but slower version:
// document["hello"].SetString(buffer, document.GetAllocator());
......
......@@ -43,7 +43,7 @@ concept Allocator {
//! C-runtime library allocator.
/*! This class is just wrapper for standard C library memory routines.
\implements Allocator
\note implements Allocator concept
*/
class CrtAllocator {
public:
......@@ -70,7 +70,7 @@ public:
The user-buffer is not deallocated by this allocator.
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
\implements Allocator
\note implements Allocator concept
*/
template <typename BaseAllocator = CrtAllocator>
class MemoryPoolAllocator {
......@@ -99,12 +99,12 @@ public:
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks.
*/
MemoryPoolAllocator(char *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
{
RAPIDJSON_ASSERT(buffer != 0);
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
chunkHead_ = (ChunkHeader*)buffer;
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
chunkHead_->capacity = size - sizeof(ChunkHeader);
chunkHead_->size = 0;
chunkHead_->next = 0;
......@@ -120,7 +120,7 @@ public:
//! Deallocates all memory chunks, excluding the user-supplied buffer.
void Clear() {
while(chunkHead_ != 0 && chunkHead_ != (ChunkHeader *)userBuffer_) {
while(chunkHead_ != 0 && chunkHead_ != userBuffer_) {
ChunkHeader* next = chunkHead_->next;
baseAllocator_->Free(chunkHead_);
chunkHead_ = next;
......@@ -153,7 +153,7 @@ public:
if (chunkHead_->size + size > chunkHead_->capacity)
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
char *buffer = (char *)(chunkHead_ + 1) + chunkHead_->size;
void *buffer = reinterpret_cast<char *>(chunkHead_ + 1) + chunkHead_->size;
chunkHead_->size += size;
return buffer;
}
......@@ -169,7 +169,7 @@ public:
// Simply expand it if it is the last allocation and there is sufficient space
if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {
size_t increment = newSize - originalSize;
size_t increment = static_cast<size_t>(newSize - originalSize);
increment = RAPIDJSON_ALIGN(increment);
if (chunkHead_->size + increment <= chunkHead_->capacity) {
chunkHead_->size += increment;
......@@ -211,7 +211,7 @@ private:
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
char *userBuffer_; //!< User supplied buffer.
void *userBuffer_; //!< User supplied buffer.
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
};
......
......@@ -92,23 +92,23 @@ public:
data_.n.i64 = i64;
if (i64 >= 0) {
flags_ |= kNumberUint64Flag;
if (!(i64 & 0xFFFFFFFF00000000LL))
if (!(static_cast<uint64_t>(i64) & UINT64_C(0xFFFFFFFF00000000)))
flags_ |= kUintFlag;
if (!(i64 & 0xFFFFFFFF80000000LL))
if (!(static_cast<uint64_t>(i64) & UINT64_C(0xFFFFFFFF80000000)))
flags_ |= kIntFlag;
}
else if (i64 >= -2147483648LL)
else if (i64 >= INT64_C(-2147483648))
flags_ |= kIntFlag;
}
//! Constructor for uint64_t value.
GenericValue(uint64_t u64) : flags_(kNumberUint64Flag) {
data_.n.u64 = u64;
if (!(u64 & 0x8000000000000000ULL))
if (!(u64 & UINT64_C(0x8000000000000000)))
flags_ |= kInt64Flag;
if (!(u64 & 0xFFFFFFFF00000000ULL))
if (!(u64 & UINT64_C(0xFFFFFFFF00000000)))
flags_ |= kUintFlag;
if (!(u64 & 0xFFFFFFFF80000000ULL))
if (!(u64 & UINT64_C(0xFFFFFFFF80000000)))
flags_ |= kIntFlag;
}
......@@ -377,7 +377,6 @@ public:
//! Get an element from array by index.
/*! \param index Zero-based index of element.
\note
\code
Value a(kArrayType);
a.PushBack(123);
......@@ -474,7 +473,7 @@ int z = a[0u].GetInt(); // This works too.
const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return data_.s.str; }
//! Get the length of string.
/*! Since rapidjson permits "\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
/*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
*/
SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return data_.s.length; }
......@@ -694,9 +693,9 @@ typedef GenericValue<UTF8<> > Value;
//! A document for parsing JSON text as DOM.
/*!
\implements Handler
\note implements Handler concept
\tparam Encoding encoding for both parsing and string storage.
\tparam Alloactor allocator for allocating memory for the DOM, and the stack during parsing.
\tparam Allocator allocator for allocating memory for the DOM, and the stack during parsing.
*/
template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
class GenericDocument : public GenericValue<Encoding, Allocator> {
......@@ -713,7 +712,7 @@ public:
//! Parse JSON text from an input stream.
/*! \tparam parseFlags Combination of ParseFlag.
\param stream Input stream to be parsed.
\param is Input stream to be parsed.
\return The document itself for fluent API.
*/
template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
......
......@@ -64,7 +64,7 @@ concept Encoding {
/*! http://en.wikipedia.org/wiki/UTF-8
http://tools.ietf.org/html/rfc3629
\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
\implements Encoding
\note implements Encoding concept
*/
template<typename CharType = char>
struct UTF8 {
......@@ -73,22 +73,22 @@ struct UTF8 {
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) {
if (codepoint <= 0x7F)
os.Put(codepoint & 0xFF);
os.Put(static_cast<Ch>(codepoint & 0xFF));
else if (codepoint <= 0x7FF) {
os.Put(0xC0 | ((codepoint >> 6) & 0xFF));
os.Put(0x80 | ((codepoint & 0x3F)));
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
}
else if (codepoint <= 0xFFFF) {
os.Put(0xE0 | ((codepoint >> 12) & 0xFF));
os.Put(0x80 | ((codepoint >> 6) & 0x3F));
os.Put(0x80 | (codepoint & 0x3F));
os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
}
else {
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
os.Put(0xF0 | ((codepoint >> 18) & 0xFF));
os.Put(0x80 | ((codepoint >> 12) & 0x3F));
os.Put(0x80 | ((codepoint >> 6) & 0x3F));
os.Put(0x80 | (codepoint & 0x3F));
os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
}
}
......@@ -204,7 +204,7 @@ struct UTF8 {
/*! http://en.wikipedia.org/wiki/UTF-16
http://tools.ietf.org/html/rfc2781
\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
\implements Encoding
\note implements Encoding concept
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
For streaming, use UTF16LE and UTF16BE, which handle endianness.
......@@ -332,8 +332,8 @@ struct UTF16BE : UTF16<CharType> {
//! UTF-32 encoding.
/*! http://en.wikipedia.org/wiki/UTF-32
\tparam Ch Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
\implements Encoding
\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
\note implements Encoding concept
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
For streaming, use UTF32LE and UTF32BE, which handle endianness.
......@@ -448,7 +448,7 @@ enum UTFType {
kUTF16LE = 1, //!< UTF-16 little endian.
kUTF16BE = 2, //!< UTF-16 big endian.
kUTF32LE = 3, //!< UTF-32 little endian.
kUTF32BE = 4, //!< UTF-32 big endian.
kUTF32BE = 4 //!< UTF-32 big endian.
};
//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
......
......@@ -8,7 +8,7 @@ namespace rapidjson {
//! File byte stream for input using fread().
/*!
\implements Stream
\note implements Stream concept
*/
class FileReadStream {
public:
......@@ -28,7 +28,7 @@ public:
Ch Peek() const { return *current_; }
Ch Take() { Ch c = *current_; Read(); return c; }
size_t Tell() const { return count_ + (current_ - buffer_); }
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
// Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); }
......
......@@ -9,8 +9,8 @@ namespace rapidjson {
//! (Depreciated) Wrapper of C file stream for input or output.
/*!
This simple wrapper does not check the validity of the stream.
\implements Stream
\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. }
\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:
......
......@@ -8,7 +8,7 @@ namespace rapidjson {
//! Wrapper of C file stream for input using fread().
/*!
\implements Stream
\note implements Stream concept
*/
class FileWriteStream {
public:
......@@ -26,13 +26,13 @@ public:
}
void PutN(char c, size_t n) {
size_t avail = bufferEnd_ - current_;
size_t avail = static_cast<size_t>(bufferEnd_ - current_);
while (n > avail) {
memset(current_, c, avail);
current_ += avail;
Flush();
n -= avail;
avail = bufferEnd_ - current_;
avail = static_cast<size_t>(bufferEnd_ - current_);
}
if (n > 0) {
......@@ -43,7 +43,7 @@ public:
void Flush() {
if (current_ != buffer_) {
fwrite(buffer_, 1, current_ - buffer_, fp_);
fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
current_ = buffer_;
}
}
......
......@@ -42,7 +42,7 @@ public:
stack_top_ = stack_ + size;
stack_end_ = stack_ + stack_capacity_;
}
T* ret = (T*)stack_top_;
T* ret = reinterpret_cast<T*>(stack_top_);
stack_top_ += sizeof(T) * count;
return ret;
}
......@@ -51,13 +51,13 @@ public:
T* Pop(size_t count) {
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
stack_top_ -= count * sizeof(T);
return (T*)stack_top_;
return reinterpret_cast<T*>(stack_top_);
}
template<typename T>
T* Top() {
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
return (T*)(stack_top_ - sizeof(T));
return reinterpret_cast<T*>(stack_top_ - sizeof(T));
}
template<typename T>
......@@ -65,7 +65,7 @@ public:
Allocator& GetAllocator() { return *allocator_; }
bool Empty() const { return stack_top_ == stack_; }
size_t GetSize() const { return stack_top_ - stack_; }
size_t GetSize() const { return static_cast<size_t>(stack_top_ - stack_); }
size_t GetCapacity() const { return stack_capacity_; }
private:
......
......@@ -8,7 +8,8 @@ namespace rapidjson {
//! Writer with indentation and spacing.
/*!
\tparam OutputStream Type of ouptut os.
\tparam Encoding Encoding of both source strings and output.
\tparam SourceEncoding Encoding of source string.
\tparam TargetEncoding Encoding of output stream.
\tparam Allocator Type of allocator for allocating memory of stack.
*/
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
......@@ -26,7 +27,7 @@ public:
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
//! Set custom indentation.
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\t', '\n', '\r').
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
\param indentCharCount Number of indent characters for each indentation level.
\note The default indentation is 4 spaces.
*/
......
......@@ -55,7 +55,7 @@ typedef unsigned __int64 uint64_t;
Currently the default uses 4 bytes alignment. User can customize this.
*/
#ifndef RAPIDJSON_ALIGN
#define RAPIDJSON_ALIGN(x) ((x + 3) & ~3)
#define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u)
#endif
///////////////////////////////////////////////////////////////////////////////
......@@ -183,7 +183,7 @@ inline void PutN(Stream& stream, Ch c, size_t n) {
// StringStream
//! Read-only string stream.
/*! \implements Stream
/*! \note implements Stream concept
*/
template <typename Encoding>
struct GenericStringStream {
......@@ -193,7 +193,7 @@ struct GenericStringStream {
Ch Peek() const { return *src_; }
Ch Take() { return *src_++; }
size_t Tell() const { return src_ - head_; }
size_t Tell() const { return static_cast<size_t>(src_ - head_); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
void Put(Ch) { RAPIDJSON_ASSERT(false); }
......@@ -211,7 +211,7 @@ typedef GenericStringStream<UTF8<> > StringStream;
//! A read-write string stream.
/*! This string stream is particularly designed for in-situ parsing.
\implements Stream
\note implements Stream concept
*/
template <typename Encoding>
struct GenericInsituStringStream {
......@@ -222,13 +222,13 @@ struct GenericInsituStringStream {
// Read
Ch Peek() { return *src_; }
Ch Take() { return *src_++; }
size_t Tell() { return src_ - head_; }
size_t Tell() { return static_cast<size_t>(src_ - head_); }
// Write
Ch* PutBegin() { return dst_ = src_; }
void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
void Flush() {}
size_t PutEnd(Ch* begin) { return dst_ - begin; }
size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
Ch* src_;
Ch* dst_;
......@@ -248,7 +248,7 @@ enum Type {
kObjectType = 3, //!< object
kArrayType = 4, //!< array
kStringType = 5, //!< string
kNumberType = 6, //!< number
kNumberType = 6 //!< number
};
} // namespace rapidjson
......
......@@ -39,7 +39,7 @@ namespace rapidjson {
enum ParseFlag {
kParseDefaultFlags = 0, //!< Default parse flags. Non-destructive parsing. Text strings are decoded into allocated buffer.
kParseInsituFlag = 1, //!< In-situ(destructive) parsing.
kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings.
kParseValidateEncodingFlag = 2 //!< Validate encoding of JSON strings.
};
///////////////////////////////////////////////////////////////////////////////
......@@ -71,7 +71,7 @@ concept Handler {
//! Default implementation of Handler.
/*! This can be used as base class of any reader handler.
\implements Handler
\note implements Handler concept
*/
template<typename Encoding = UTF8<> >
struct BaseReaderHandler {
......@@ -96,7 +96,7 @@ struct BaseReaderHandler {
// SkipWhitespace
//! Skip the JSON white spaces in a stream.
/*! \param stream A input stream for skipping white spaces.
/*! \param is A input stream for skipping white spaces.
\note This function has SSE2/SSE4.2 specialization.
*/
template<typename InputStream>
......@@ -216,7 +216,7 @@ public:
/*! \tparam parseFlags Combination of ParseFlag.
\tparam InputStream Type of input stream.
\tparam Handler Type of handler which must implement Handler concept.
\param stream Input stream to be parsed.
\param is Input stream to be parsed.
\param handler The handler to receive events.
\return Whether the parsing is successful.
*/
......@@ -368,7 +368,7 @@ private:
for (int i = 0; i < 4; i++) {
Ch c = s.Take();
codepoint <<= 4;
codepoint += c;
codepoint += static_cast<unsigned>(c);
if (c >= '0' && c <= '9')
codepoint -= '0';
else if (c >= 'A' && c <= 'F')
......@@ -494,7 +494,7 @@ private:
s.Take();
}
else if (s.Peek() >= '1' && s.Peek() <= '9') {
i = s.Take() - '0';
i = static_cast<unsigned>(s.Take() - '0');
if (minus)
while (s.Peek() >= '0' && s.Peek() <= '9') {
......@@ -504,7 +504,7 @@ private:
break;
}
}
i = i * 10 + (s.Take() - '0');
i = i * 10 + static_cast<unsigned>(s.Take() - '0');
}
else
while (s.Peek() >= '0' && s.Peek() <= '9') {
......@@ -514,7 +514,7 @@ private:
break;
}
}
i = i * 10 + (s.Take() - '0');
i = i * 10 + static_cast<unsigned>(s.Take() - '0');
}
}
else
......@@ -527,21 +527,21 @@ private:
i64 = i;
if (minus)
while (s.Peek() >= '0' && s.Peek() <= '9') {
if (i64 >= 922337203685477580uLL) // 2^63 = 9223372036854775808
if (i64 != 922337203685477580uLL || s.Peek() > '8') {
if (i64 >= UINT64_C(922337203685477580)) // 2^63 = 9223372036854775808
if (i64 != UINT64_C(922337203685477580) || s.Peek() > '8') {
useDouble = true;
break;
}
i64 = i64 * 10 + (s.Take() - '0');
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
}
else
while (s.Peek() >= '0' && s.Peek() <= '9') {
if (i64 >= 1844674407370955161uLL) // 2^64 - 1 = 18446744073709551615
if (i64 != 1844674407370955161uLL || s.Peek() > '5') {
if (i64 >= UINT64_C(1844674407370955161)) // 2^64 - 1 = 18446744073709551615
if (i64 != UINT64_C(1844674407370955161) || s.Peek() > '5') {
useDouble = true;
break;
}
i64 = i64 * 10 + (s.Take() - '0');
i64 = i64 * 10 + static_cast<unsigned>(s.Take() - '0');
}
}
......
......@@ -10,7 +10,7 @@ namespace rapidjson {
/*!
\tparam Encoding Encoding of the stream.
\tparam Allocator type for allocating memory buffer.
\implements Stream
\note implements Stream concept
*/
template <typename Encoding, typename Allocator = CrtAllocator>
struct GenericStringBuffer {
......
......@@ -27,7 +27,7 @@ namespace rapidjson {
\tparam OutputStream Type of output stream.
\tparam SourceEncoding Encoding of both source strings.
\tparam TargetEncoding Encoding of and output stream.
\implements Handler
\note implements Handler concept
*/
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename Allocator = MemoryPoolAllocator<> >
class Writer {
......@@ -97,9 +97,9 @@ public:
protected:
//! Information for each nested level
struct Level {
Level(bool inArray_) : inArray(inArray_), valueCount(0) {}
bool inArray; //!< true if in array, otherwise in object
Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
size_t valueCount; //!< number of values in this level
bool inArray; //!< true if in array, otherwise in object
};
static const size_t kDefaultLevelDepth = 32;
......@@ -164,7 +164,7 @@ protected:
//! \todo Optimization with custom double-to-string converter.
void WriteDouble(double d) {
char buffer[100];
#if _MSC_VER
#ifdef _MSC_VER
int ret = sprintf_s(buffer, sizeof(buffer), "%g", d);
#else
int ret = snprintf(buffer, sizeof(buffer), "%g", d);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment