Skip to content

Commit ceef7f5

Browse files
committed
copied impl of StyledStreamWriter
1 parent 77ce057 commit ceef7f5

File tree

1 file changed

+215
-4
lines changed

1 file changed

+215
-4
lines changed

src/lib_json/json_writer.cpp

Lines changed: 215 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -667,27 +667,238 @@ bool StyledStreamWriter::hasCommentForValue(const Value& value) {
667667

668668
struct BuiltStyledStreamWriter : public StreamWriter
669669
{
670-
mutable StyledStreamWriter old_;
671-
672670
BuiltStyledStreamWriter(
673671
std::ostream* sout,
674672
std::string const& indentation,
675673
StreamWriter::CommentStyle cs);
676674
virtual int write(Value const& root) const;
675+
private:
676+
void writeValue(const Value& value);
677+
void writeArrayValue(const Value& value);
678+
bool isMultineArray(const Value& value);
679+
void pushValue(const std::string& value);
680+
void writeIndent();
681+
void writeWithIndent(const std::string& value);
682+
void indent();
683+
void unindent();
684+
void writeCommentBeforeValue(const Value& root);
685+
void writeCommentAfterValueOnSameLine(const Value& root);
686+
bool hasCommentForValue(const Value& value);
687+
static std::string normalizeEOL(const std::string& text);
688+
689+
typedef std::vector<std::string> ChildValues;
690+
691+
ChildValues childValues_;
692+
std::ostream* document_;
693+
std::string indentString_;
694+
int rightMargin_;
695+
std::string indentation_;
696+
bool addChildValues_;
677697
};
678698
BuiltStyledStreamWriter::BuiltStyledStreamWriter(
679699
std::ostream* sout,
680700
std::string const& indentation,
681701
StreamWriter::CommentStyle cs)
682702
: StreamWriter(sout)
683-
, old_(indentation)
703+
, indentation_(indentation)
704+
, rightMargin_(74)
684705
{
685706
}
686707
int BuiltStyledStreamWriter::write(Value const& root) const
687708
{
688-
old_.write(sout_, root);
709+
write(sout_, root);
689710
return 0;
690711
}
712+
void BuiltStyledStreamWriter::write(std::ostream& out, const Value& root) {
713+
document_ = &out;
714+
addChildValues_ = false;
715+
indentString_ = "";
716+
writeCommentBeforeValue(root);
717+
writeValue(root);
718+
writeCommentAfterValueOnSameLine(root);
719+
*document_ << "\n";
720+
document_ = NULL; // Forget the stream, for safety.
721+
}
722+
723+
void BuiltStyledStreamWriter::writeValue(const Value& value) {
724+
switch (value.type()) {
725+
case nullValue:
726+
pushValue("null");
727+
break;
728+
case intValue:
729+
pushValue(valueToString(value.asLargestInt()));
730+
break;
731+
case uintValue:
732+
pushValue(valueToString(value.asLargestUInt()));
733+
break;
734+
case realValue:
735+
pushValue(valueToString(value.asDouble()));
736+
break;
737+
case stringValue:
738+
pushValue(valueToQuotedString(value.asCString()));
739+
break;
740+
case booleanValue:
741+
pushValue(valueToString(value.asBool()));
742+
break;
743+
case arrayValue:
744+
writeArrayValue(value);
745+
break;
746+
case objectValue: {
747+
Value::Members members(value.getMemberNames());
748+
if (members.empty())
749+
pushValue("{}");
750+
else {
751+
writeWithIndent("{");
752+
indent();
753+
Value::Members::iterator it = members.begin();
754+
for (;;) {
755+
const std::string& name = *it;
756+
const Value& childValue = value[name];
757+
writeCommentBeforeValue(childValue);
758+
writeWithIndent(valueToQuotedString(name.c_str()));
759+
*document_ << " : ";
760+
writeValue(childValue);
761+
if (++it == members.end()) {
762+
writeCommentAfterValueOnSameLine(childValue);
763+
break;
764+
}
765+
*document_ << ",";
766+
writeCommentAfterValueOnSameLine(childValue);
767+
}
768+
unindent();
769+
writeWithIndent("}");
770+
}
771+
} break;
772+
}
773+
}
774+
775+
void BuiltStyledStreamWriter::writeArrayValue(const Value& value) {
776+
unsigned size = value.size();
777+
if (size == 0)
778+
pushValue("[]");
779+
else {
780+
bool isArrayMultiLine = isMultineArray(value);
781+
if (isArrayMultiLine) {
782+
writeWithIndent("[");
783+
indent();
784+
bool hasChildValue = !childValues_.empty();
785+
unsigned index = 0;
786+
for (;;) {
787+
const Value& childValue = value[index];
788+
writeCommentBeforeValue(childValue);
789+
if (hasChildValue)
790+
writeWithIndent(childValues_[index]);
791+
else {
792+
writeIndent();
793+
writeValue(childValue);
794+
}
795+
if (++index == size) {
796+
writeCommentAfterValueOnSameLine(childValue);
797+
break;
798+
}
799+
*document_ << ",";
800+
writeCommentAfterValueOnSameLine(childValue);
801+
}
802+
unindent();
803+
writeWithIndent("]");
804+
} else // output on a single line
805+
{
806+
assert(childValues_.size() == size);
807+
*document_ << "[ ";
808+
for (unsigned index = 0; index < size; ++index) {
809+
if (index > 0)
810+
*document_ << ", ";
811+
*document_ << childValues_[index];
812+
}
813+
*document_ << " ]";
814+
}
815+
}
816+
}
817+
818+
bool BuiltStyledStreamWriter::isMultineArray(const Value& value) {
819+
int size = value.size();
820+
bool isMultiLine = size * 3 >= rightMargin_;
821+
childValues_.clear();
822+
for (int index = 0; index < size && !isMultiLine; ++index) {
823+
const Value& childValue = value[index];
824+
isMultiLine =
825+
isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
826+
childValue.size() > 0);
827+
}
828+
if (!isMultiLine) // check if line length > max line length
829+
{
830+
childValues_.reserve(size);
831+
addChildValues_ = true;
832+
int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
833+
for (int index = 0; index < size; ++index) {
834+
writeValue(value[index]);
835+
lineLength += int(childValues_[index].length());
836+
}
837+
addChildValues_ = false;
838+
isMultiLine = isMultiLine || lineLength >= rightMargin_;
839+
}
840+
return isMultiLine;
841+
}
842+
843+
void BuiltStyledStreamWriter::pushValue(const std::string& value) {
844+
if (addChildValues_)
845+
childValues_.push_back(value);
846+
else
847+
*document_ << value;
848+
}
849+
850+
void BuiltStyledStreamWriter::writeIndent() {
851+
/*
852+
Some comments in this method would have been nice. ;-)
853+
854+
if ( !document_.empty() )
855+
{
856+
char last = document_[document_.length()-1];
857+
if ( last == ' ' ) // already indented
858+
return;
859+
if ( last != '\n' ) // Comments may add new-line
860+
*document_ << '\n';
861+
}
862+
*/
863+
*document_ << '\n' << indentString_;
864+
}
865+
866+
void BuiltStyledStreamWriter::writeWithIndent(const std::string& value) {
867+
writeIndent();
868+
*document_ << value;
869+
}
870+
871+
void BuiltStyledStreamWriter::indent() { indentString_ += indentation_; }
872+
873+
void BuiltStyledStreamWriter::unindent() {
874+
assert(indentString_.size() >= indentation_.size());
875+
indentString_.resize(indentString_.size() - indentation_.size());
876+
}
877+
878+
void BuiltStyledStreamWriter::writeCommentBeforeValue(const Value& root) {
879+
if (!root.hasComment(commentBefore))
880+
return;
881+
*document_ << root.getComment(commentBefore);
882+
*document_ << "\n";
883+
}
884+
885+
void BuiltStyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
886+
if (root.hasComment(commentAfterOnSameLine))
887+
*document_ << " " + root.getComment(commentAfterOnSameLine);
888+
889+
if (root.hasComment(commentAfter)) {
890+
*document_ << "\n";
891+
*document_ << root.getComment(commentAfter);
892+
*document_ << "\n";
893+
}
894+
}
895+
896+
bool BuiltStyledStreamWriter::hasCommentForValue(const Value& value) {
897+
return value.hasComment(commentBefore) ||
898+
value.hasComment(commentAfterOnSameLine) ||
899+
value.hasComment(commentAfter);
900+
}
901+
691902
StreamWriter::StreamWriter(std::ostream* sout)
692903
: sout_(*sout)
693904
{

0 commit comments

Comments
 (0)