Skip to content

Commit

Permalink
Merge pull request #67 from miloyip/issue66writerassertion
Browse files Browse the repository at this point in the history
Fix #66 by adding Writer::Reset() and Writer::IsComplete()
  • Loading branch information
miloyip committed Jul 15, 2014
2 parents 2e0b3de + 27101d9 commit c5a4926
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 46 deletions.
31 changes: 17 additions & 14 deletions include/rapidjson/prettywriter.h
Expand Up @@ -78,13 +78,13 @@ class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding,
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;

if (!empty) {
Base::os_.Put('\n');
Base::os_->Put('\n');
WriteIndent();
}
if (!Base::WriteEndObject())
return false;
if (Base::level_stack_.Empty()) // end of json text
Base::os_.Flush();
Base::os_->Flush();
return true;
}

Expand All @@ -101,13 +101,13 @@ class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding,
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;

if (!empty) {
Base::os_.Put('\n');
Base::os_->Put('\n');
WriteIndent();
}
if (!Base::WriteEndArray())
return false;
if (Base::level_stack_.Empty()) // end of json text
Base::os_.Flush();
Base::os_->Flush();
return true;
}

Expand Down Expand Up @@ -137,26 +137,26 @@ class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding,

if (level->inArray) {
if (level->valueCount > 0) {
Base::os_.Put(','); // add comma if it is not the first element in array
Base::os_.Put('\n');
Base::os_->Put(','); // add comma if it is not the first element in array
Base::os_->Put('\n');
}
else
Base::os_.Put('\n');
Base::os_->Put('\n');
WriteIndent();
}
else { // in object
if (level->valueCount > 0) {
if (level->valueCount % 2 == 0) {
Base::os_.Put(',');
Base::os_.Put('\n');
Base::os_->Put(',');
Base::os_->Put('\n');
}
else {
Base::os_.Put(':');
Base::os_.Put(' ');
Base::os_->Put(':');
Base::os_->Put(' ');
}
}
else
Base::os_.Put('\n');
Base::os_->Put('\n');

if (level->valueCount % 2 == 0)
WriteIndent();
Expand All @@ -165,13 +165,16 @@ class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding,
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
level->valueCount++;
}
else
else {
RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
Base::hasRoot_ = true;
}
}

void WriteIndent() {
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
PutN(Base::os_, indentChar_, count);
PutN(*Base::os_, indentChar_, count);
}

Ch indentChar_;
Expand Down
95 changes: 66 additions & 29 deletions include/rapidjson/writer.h
Expand Up @@ -41,8 +41,41 @@ class Writer {
\param levelDepth Initial capacity of stack.
*/
Writer(OutputStream& os, Allocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
os_(os), level_stack_(allocator, levelDepth * sizeof(Level)),
doublePrecision_(kDefaultDoublePrecision) {}
os_(&os), level_stack_(allocator, levelDepth * sizeof(Level)),
doublePrecision_(kDefaultDoublePrecision), hasRoot_(false) {}

//! Reset the writer with a new stream.
/*!
This function reset the writer with a new stream and default settings,
in order to make a Writer object reusable for output multiple JSONs.
\param os New output stream.
\code
Writer<OutputStream> writer(os1);
writer.StartObject();
// ...
writer.EndObject();
writer.Reset(os2);
writer.StartObject();
// ...
writer.EndObject();
\endcode
*/
void Reset(OutputStream& os) {
os_ = &os;
doublePrecision_ = kDefaultDoublePrecision;
hasRoot_ = false;
level_stack_.Clear();
}

//! Checks whether the output is a complete JSON.
/*!
A complete JSON has a complete root object or array.
*/
bool IsComplete() const {
return hasRoot_ && level_stack_.Empty();
}

//! Set the number of significant digits for \c double values
/*! When writing a \c double value to the \c OutputStream, the number
Expand Down Expand Up @@ -103,7 +136,7 @@ class Writer {
level_stack_.template Pop<Level>(1);
bool ret = WriteEndObject();
if (level_stack_.Empty()) // end of json text
os_.Flush();
os_->Flush();
return ret;
}

Expand All @@ -120,7 +153,7 @@ class Writer {
level_stack_.template Pop<Level>(1);
bool ret = WriteEndArray();
if (level_stack_.Empty()) // end of json text
os_.Flush();
os_->Flush();
return ret;
}
//@}
Expand Down Expand Up @@ -161,22 +194,22 @@ class Writer {
static const size_t kDefaultLevelDepth = 32;

bool WriteNull() {
os_.Put('n'); os_.Put('u'); os_.Put('l'); os_.Put('l'); return true;
os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true;
}

bool WriteBool(bool b) {
if (b) {
os_.Put('t'); os_.Put('r'); os_.Put('u'); os_.Put('e');
os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e');
}
else {
os_.Put('f'); os_.Put('a'); os_.Put('l'); os_.Put('s'); os_.Put('e');
os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e');
}
return true;
}

bool WriteInt(int i) {
if (i < 0) {
os_.Put('-');
os_->Put('-');
i = -i;
}
return WriteUint((unsigned)i);
Expand All @@ -192,14 +225,14 @@ class Writer {

do {
--p;
os_.Put(*p);
os_->Put(*p);
} while (p != buffer);
return true;
}

bool WriteInt64(int64_t i64) {
if (i64 < 0) {
os_.Put('-');
os_->Put('-');
i64 = -i64;
}
WriteUint64((uint64_t)i64);
Expand All @@ -216,7 +249,7 @@ class Writer {

do {
--p;
os_.Put(*p);
os_->Put(*p);
} while (p != buffer);
return true;
}
Expand All @@ -233,7 +266,7 @@ class Writer {
int ret = RAPIDJSON_SNPRINTF(buffer, sizeof(buffer), "%.*g", doublePrecision_, d);
RAPIDJSON_ASSERT(ret >= 1);
for (int i = 0; i < ret; i++)
os_.Put(buffer[i]);
os_->Put(buffer[i]);
return true;
}
#undef RAPIDJSON_SNPRINTF
Expand All @@ -252,54 +285,58 @@ class Writer {
#undef Z16
};

os_.Put('\"');
os_->Put('\"');
GenericStringStream<SourceEncoding> is(str);
while (is.Tell() < length) {
const Ch c = is.Peek();
if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) {
is.Take();
os_.Put('\\');
os_.Put(escape[(unsigned char)c]);
os_->Put('\\');
os_->Put(escape[(unsigned char)c]);
if (escape[(unsigned char)c] == 'u') {
os_.Put('0');
os_.Put('0');
os_.Put(hexDigits[(unsigned char)c >> 4]);
os_.Put(hexDigits[(unsigned char)c & 0xF]);
os_->Put('0');
os_->Put('0');
os_->Put(hexDigits[(unsigned char)c >> 4]);
os_->Put(hexDigits[(unsigned char)c & 0xF]);
}
}
else
Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, os_);
Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, *os_);
}
os_.Put('\"');
os_->Put('\"');
return true;
}

bool WriteStartObject() { os_.Put('{'); return true; }
bool WriteEndObject() { os_.Put('}'); return true; }
bool WriteStartArray() { os_.Put('['); return true; }
bool WriteEndArray() { os_.Put(']'); return true; }
bool WriteStartObject() { os_->Put('{'); return true; }
bool WriteEndObject() { os_->Put('}'); return true; }
bool WriteStartArray() { os_->Put('['); return true; }
bool WriteEndArray() { os_->Put(']'); return true; }

void Prefix(Type type) {
(void)type;
if (level_stack_.GetSize() != 0) { // this value is not at root
Level* level = level_stack_.template Top<Level>();
if (level->valueCount > 0) {
if (level->inArray)
os_.Put(','); // add comma if it is not the first element in array
os_->Put(','); // add comma if it is not the first element in array
else // in object
os_.Put((level->valueCount % 2 == 0) ? ',' : ':');
os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
}
if (!level->inArray && level->valueCount % 2 == 0)
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
level->valueCount++;
}
else
else {
RAPIDJSON_ASSERT(type == kObjectType || type == kArrayType);
RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
hasRoot_ = true;
}
}

OutputStream& os_;
OutputStream* os_;
internal::Stack<Allocator> level_stack_;
int doublePrecision_;
bool hasRoot_;

static const int kDefaultDoublePrecision = 6;

Expand Down
18 changes: 18 additions & 0 deletions test/unittest/unittest.h
Expand Up @@ -56,4 +56,22 @@ inline void TempFilename(char *filename) {
filename[i] = filename[i + 1];
}

// Use exception for catching assert
#if _MSC_VER
#pragma warning(disable : 4127)
#endif

class AssertException : public std::exception {
public:
AssertException(const char* w) : what_(w) {}
AssertException(const AssertException& other) : what_(other.what_) {}
AssertException& operator=(const AssertException& rhs) { what_ = rhs.what_; return *this; }
virtual const char* what() const throw() { return what_; }

private:
const char* what_;
};

#define RAPIDJSON_ASSERT(x) if (!(x)) throw AssertException(RAPIDJSON_STRINGIFY(x))

#endif // UNITTEST_H_

0 comments on commit c5a4926

Please sign in to comment.