@@ -82,73 +82,77 @@ class SimpleJsonWriter
82
82
public:
83
83
explicit SimpleJsonWriter (std::ostringstream& stream) : stream_(stream)
84
84
{
85
+ stream_.imbue (std::locale::classic ());
85
86
}
86
87
87
88
void
88
89
startObject () const
89
90
{
90
- stream_ << " { " ;
91
+ stream_. put ( ' { ' ) ;
91
92
}
92
93
void
93
94
endObject () const
94
95
{
95
96
stream_.seekp (-1 , std::ios_base::end);
96
- stream_ << " }," ;
97
+ stream_. write ( " }," , 2 ) ;
97
98
}
98
99
void
99
100
writeKey (std::string_view key) const
100
101
{
101
102
writeString (key);
102
103
stream_.seekp (-1 , std::ios_base::end);
103
- stream_ << " : " ;
104
+ stream_. put ( ' : ' ) ;
104
105
}
105
106
void
106
107
startArray () const
107
108
{
108
- stream_ << " [ " ;
109
+ stream_. put ( ' [ ' ) ;
109
110
}
110
111
void
111
112
endArray () const
112
113
{
113
114
stream_.seekp (-1 , std::ios_base::end);
114
- stream_ << " ]," ;
115
+ stream_. write ( " ]," , 2 ) ;
115
116
}
116
117
void
117
118
writeString (std::string_view str) const
118
119
{
119
- stream_ << " \" " ;
120
+ stream_. put ( ' " ' ) ;
120
121
escape (str, stream_);
121
- stream_ << " \" ," ;
122
+ stream_. write ( " \" ," , 2 ) ;
122
123
}
123
- void
124
+ std::string_view
124
125
writeInt (std::int64_t val) const
125
126
{
126
- stream_ << val << " , " ;
127
+ return pushNumber ( val, stream_) ;
127
128
}
128
- void
129
+ std::string_view
129
130
writeUInt (std::uint64_t val) const
130
131
{
131
- stream_ << val << " , " ;
132
+ return pushNumber ( val, stream_) ;
132
133
}
133
- void
134
+ std::string_view
134
135
writeDouble (double val) const
135
136
{
136
- stream_ << val << " , " ;
137
+ return pushNumber ( val, stream_) ;
137
138
}
138
- void
139
+ std::string_view
139
140
writeBool (bool val) const
140
141
{
141
- stream_ << (val ? " true," : " false," );
142
+ auto str = val ? " true," : " false," ;
143
+ stream_.write (str, std::strlen (str));
144
+ return str;
142
145
}
143
146
void
144
147
writeNull () const
145
148
{
146
- stream_ << " null" << " ," ;
149
+ stream_.write (" null" , std::strlen (" null" ));
150
+ stream_.put (' ,' );
147
151
}
148
152
void
149
153
writeRaw (std::string_view str) const
150
154
{
151
- stream_ << str;
155
+ stream_. write (str. data (), str. length ()) ;
152
156
}
153
157
154
158
[[nodiscard]] std::string
@@ -160,11 +164,69 @@ class SimpleJsonWriter
160
164
}
161
165
162
166
private:
167
+ template <typename T>
168
+ static std::string_view
169
+ pushNumber (T val, std::ostringstream& stream)
170
+ {
171
+ static char buffer[128 ];
172
+ auto result = std::to_chars (std::begin (buffer), std::end (buffer), val);
173
+ *result.ptr = ' ,' ;
174
+ auto len = result.ptr - std::begin (buffer);
175
+ stream.write (buffer, len + 1 );
176
+ return {buffer, static_cast <size_t >(len)};
177
+ }
178
+
163
179
static void
164
180
escape (std::string_view str, std::ostringstream& os)
165
181
{
166
- // TODO: Support it
167
- os << str;
182
+ static constexpr char HEX[] = " 0123456789ABCDEF" ;
183
+
184
+ const char * p = str.data ();
185
+ const char * end = p + str.size ();
186
+ const char * chunk = p;
187
+
188
+ while (p < end) {
189
+ auto c = static_cast <unsigned char >(*p);
190
+
191
+ // JSON requires escaping for <0x20 and the two specials below.
192
+ bool needsEscape = (c < 0x20 ) || (c == ' "' ) || (c == ' \\ ' );
193
+
194
+ if (!needsEscape) {
195
+ ++p;
196
+ continue ;
197
+ }
198
+
199
+ // Flush the preceding safe run in one go.
200
+ if (chunk != p)
201
+ os.write (chunk, p - chunk);
202
+
203
+ switch (c) {
204
+ case ' "' : os.write (" \\\" " , 2 ); break ;
205
+ case ' \\ ' : os.write (" \\\\ " , 2 ); break ;
206
+ case ' \b ' : os.write (" \\ b" , 2 ); break ;
207
+ case ' \f ' : os.write (" \\ f" , 2 ); break ;
208
+ case ' \n ' : os.write (" \\ n" , 2 ); break ;
209
+ case ' \r ' : os.write (" \\ r" , 2 ); break ;
210
+ case ' \t ' : os.write (" \\ t" , 2 ); break ;
211
+ default : {
212
+ // Other C0 controls -> \u00XX (JSON compliant)
213
+ char buf[6 ]{
214
+ ' \\ ' ,' u' ,' 0' ,' 0' ,
215
+ HEX[(c >> 4 ) & 0xF ],
216
+ HEX[c & 0xF ]
217
+ };
218
+ os.write (buf, 6 );
219
+ break ;
220
+ }
221
+ }
222
+
223
+ ++p;
224
+ chunk = p;
225
+ }
226
+
227
+ // Flush trailing safe run
228
+ if (chunk != p)
229
+ os.write (chunk, p - chunk);
168
230
}
169
231
170
232
std::ostringstream& stream_;
@@ -769,6 +831,13 @@ using logwstream = basic_logstream<wchar_t>;
769
831
namespace ripple ::log {
770
832
771
833
namespace detail {
834
+
835
+ template <typename T>
836
+ concept CanToChars = requires (T val)
837
+ {
838
+ { to_chars (std::declval<char *>(), std::declval<char *>(), val) } -> std::convertible_to<std::to_chars_result>;
839
+ };
840
+
772
841
template <typename T>
773
842
void
774
843
setJsonValue (
@@ -781,34 +850,35 @@ setJsonValue(
781
850
writer.writeKey (name);
782
851
if constexpr (std::is_integral_v<ValueType>)
783
852
{
853
+ std::string_view sv;
784
854
if constexpr (std::is_signed_v<ValueType>)
785
855
{
786
- writer.writeInt (value);
856
+ sv = writer.writeInt (value);
787
857
}
788
858
else
789
859
{
790
- writer.writeUInt (value);
860
+ sv = writer.writeUInt (value);
791
861
}
792
862
if (outStream)
793
863
{
794
- (* outStream) << value ;
864
+ outStream-> write (sv. data (), sv. size ()) ;
795
865
}
796
866
}
797
867
else if constexpr (std::is_floating_point_v<ValueType>)
798
868
{
799
- writer.writeDouble (value);
869
+ auto sv = writer.writeDouble (value);
800
870
801
871
if (outStream)
802
872
{
803
- (* outStream) << value ;
873
+ outStream-> write (sv. data (), sv. size ()) ;
804
874
}
805
875
}
806
876
else if constexpr (std::is_same_v<ValueType, bool >)
807
877
{
808
- writer.writeBool (value);
878
+ auto sv = writer.writeBool (value);
809
879
if (outStream)
810
880
{
811
- (* outStream) << value ;
881
+ outStream-> write (sv. data (), sv. size ()) ;
812
882
}
813
883
}
814
884
else if constexpr (
@@ -818,20 +888,38 @@ setJsonValue(
818
888
writer.writeString (value);
819
889
if (outStream)
820
890
{
821
- (* outStream) << value;
891
+ outStream-> write (value, std::strlen ( value)) ;
822
892
}
823
893
}
824
894
else if constexpr (std::is_same_v<ValueType, std::string>)
825
895
{
826
896
writer.writeString (value);
827
897
if (outStream)
828
898
{
829
- (* outStream) << value;
899
+ outStream-> write (value. c_str (), value. length ()) ;
830
900
}
831
901
}
832
902
else
833
903
{
904
+ if constexpr (CanToChars<ValueType>)
905
+ {
906
+ char buffer[1024 ];
907
+ std::to_chars_result result = to_chars (std::begin (buffer), std::end (buffer), value);
908
+ if (result.ec == std::errc{})
909
+ {
910
+ std::string_view sv;
911
+ sv = {std::begin (buffer), result.ptr };
912
+ writer.writeString (sv);
913
+ if (outStream)
914
+ {
915
+ outStream->write (sv.data (), sv.size ());
916
+ }
917
+ return ;
918
+ }
919
+ }
920
+
834
921
std::ostringstream oss;
922
+ oss.imbue (std::locale::classic ());
835
923
oss << value;
836
924
837
925
auto str = oss.str ();
@@ -840,7 +928,7 @@ setJsonValue(
840
928
841
929
if (outStream)
842
930
{
843
- (* outStream) << str;
931
+ outStream-> write (str. c_str (), static_cast <std::streamsize>( str. size ())) ;
844
932
}
845
933
}
846
934
}
0 commit comments