@@ -843,6 +843,45 @@ namespace glz
843
843
template <class T >
844
844
concept array_padding_known =
845
845
requires { typename T::value_type; } && (required_padding<typename T::value_type>() > 0 );
846
+
847
+ template <class Container >
848
+ using iterator_pair_type = typename std::iterator_traits<decltype(std::begin(std::declval<Container&>()))>::value_type;
849
+
850
+ template <class Container , typename Iterator = iterator_pair_type<Container>>
851
+ struct iterator_second_impl ;
852
+
853
+ template <class Container , typename Iterator>
854
+ requires has_value_type<Iterator>
855
+ struct iterator_second_impl <Container, Iterator> {
856
+ using type = typename Iterator::value_type;
857
+ };
858
+
859
+ template <class Container , typename Iterator>
860
+ requires (!has_value_type<Iterator> && has_second_type<Iterator>)
861
+ struct iterator_second_impl<Container, Iterator> {
862
+ using type = typename Iterator::second_type;
863
+ };
864
+
865
+ template <class Container >
866
+ using iterator_second_type = typename iterator_second_impl<Container>::type;
867
+
868
+ template <class Container , typename Iterator = iterator_pair_type<Container>>
869
+ struct iterator_first_impl ;
870
+
871
+ template <class Container , typename Iterator>
872
+ requires has_value_type<Iterator>
873
+ struct iterator_first_impl <Container, Iterator> {
874
+ using type = typename Iterator::value_type;
875
+ };
876
+
877
+ template <class Container , typename Iterator>
878
+ requires (!has_value_type<Iterator> && has_first_type<Iterator>)
879
+ struct iterator_first_impl<Container, Iterator> {
880
+ using type = typename Iterator::first_type;
881
+ };
882
+
883
+ template <class Container >
884
+ using iterator_first_type = typename iterator_first_impl<Container>::type;
846
885
847
886
template <class T >
848
887
requires (writable_array_t <T> || writable_map_t <T>)
@@ -1033,107 +1072,101 @@ namespace glz
1033
1072
}
1034
1073
}
1035
1074
1036
- template <auto Opts>
1075
+ template <auto Opts, class B >
1037
1076
requires (writable_map_t <T> || (map_like_array && Opts.concatenate == true ))
1038
- static void op (auto && value, is_context auto && ctx, auto &&... args )
1077
+ static void op (auto && value, is_context auto && ctx, B&& b, auto && ix )
1039
1078
{
1040
1079
if constexpr (not has_opening_handled (Opts)) {
1041
- dump<' {' >(args... );
1080
+ dump<' {' >(b, ix );
1042
1081
}
1043
1082
1044
1083
if (!empty_range (value)) {
1045
1084
if constexpr (!has_opening_handled (Opts)) {
1046
1085
if constexpr (Opts.prettify ) {
1047
1086
ctx.indentation_level += Opts.indentation_width ;
1048
- dump_newline_indent<Opts.indentation_char >(ctx.indentation_level , args...);
1049
- }
1050
- }
1051
-
1052
- auto write_first_entry = [&ctx, &args...](auto && it) {
1053
- if constexpr (requires {
1054
- it->first ;
1055
- it->second ;
1056
- }) {
1057
- // Allow non-const access, unlike ranges
1058
- if (skip_member<Opts>(it->second )) {
1059
- return true ;
1060
- }
1061
- write_pair_content<Opts>(it->first , it->second , ctx, args...);
1062
- return false ;
1063
- }
1064
- else {
1065
- const auto & [key, entry_val] = *it;
1066
- if (skip_member<Opts>(entry_val)) {
1067
- return true ;
1087
+ if constexpr (vector_like<B>) {
1088
+ if (const auto k = ix + ctx.indentation_level + write_padding_bytes; k > b.size ()) [[unlikely]] {
1089
+ b.resize (2 * k);
1090
+ }
1068
1091
}
1069
- write_pair_content<Opts>(key, entry_val, ctx, args...);
1070
- return false ;
1092
+ std::memcpy (&b[ix], " \n " , 1 );
1093
+ ++ix;
1094
+ std::memset (&b[ix], Opts.indentation_char , ctx.indentation_level );
1095
+ ix += ctx.indentation_level ;
1071
1096
}
1072
- };
1073
-
1074
- auto it = std::begin (value);
1075
- [[maybe_unused]] bool starting = write_first_entry (it);
1076
- for (++it; it != std::end (value); ++it) {
1077
- // I couldn't find an easy way around this code duplication
1078
- // Ranges need to be decomposed with const auto& [...],
1079
- // but we don't want to const qualify our maps for the sake of reflection writing
1080
- // we need to be able to populate the tuple of pointers when writing with reflection
1081
- if constexpr (requires {
1082
- it->first ;
1083
- it->second ;
1084
- }) {
1085
- if (skip_member<Opts>(it->second )) {
1086
- continue ;
1087
- }
1097
+ }
1098
+
1099
+ using val_t = iterator_second_type<T>; // the type of value in each [key, value] pair
1100
+
1101
+ if constexpr (not always_skipped<val_t >)
1102
+ {
1103
+ if constexpr (null_t <val_t > && Opts.skip_null_members )
1104
+ {
1105
+ auto write_first_entry = [&](auto && it) {
1106
+ auto && [key, entry_val] = *it;
1107
+ if (skip_member<Opts>(entry_val)) {
1108
+ return true ;
1109
+ }
1110
+ write_pair_content<Opts>(key, entry_val, ctx, b, ix);
1111
+ return false ;
1112
+ };
1113
+
1114
+ auto it = std::begin (value);
1115
+ bool first = write_first_entry (it);
1116
+ ++it;
1117
+ for (const auto end = std::end (value); it != end; ++it) {
1118
+ auto && [key, entry_val] = *it;
1119
+ if (skip_member<Opts>(entry_val)) {
1120
+ continue ;
1121
+ }
1088
1122
1089
- // When Opts.skip_null_members, *any* entry may be skipped, meaning separator dumping must be
1090
- // conditional for every entry. Avoid this branch when not skipping null members.
1091
- // Alternatively, write separator after each entry except last but then branch is permanent
1092
- if constexpr (Opts.skip_null_members ) {
1093
- if (!starting) {
1094
- write_object_entry_separator<Opts>(ctx, args...);
1123
+ // When Opts.skip_null_members, *any* entry may be skipped, meaning separator dumping must be
1124
+ // conditional for every entry.
1125
+ // Alternatively, write separator after each entry except last but then branch is permanent
1126
+ if (not first) {
1127
+ write_object_entry_separator<Opts>(ctx, b, ix);
1095
1128
}
1096
- }
1097
- else {
1098
- write_object_entry_separator<Opts>(ctx, args...);
1099
- }
1100
1129
1101
- write_pair_content<Opts>(it->first , it->second , ctx, args...);
1102
- }
1103
- else {
1104
- const auto & [key, entry_val] = *it;
1105
- if (skip_member<Opts>(entry_val)) {
1106
- continue ;
1107
- }
1130
+ write_pair_content<Opts>(key, entry_val, ctx, b, ix);
1108
1131
1109
- // When Opts.skip_null_members, *any* entry may be skipped, meaning separator dumping must be
1110
- // conditional for every entry. Avoid this branch when not skipping null members.
1111
- // Alternatively, write separator after each entry except last but then branch is permanent
1112
- if constexpr (Opts.skip_null_members ) {
1113
- if (!starting) {
1114
- write_object_entry_separator<Opts>(ctx, args...);
1115
- }
1132
+ first = false ;
1116
1133
}
1117
- else {
1118
- write_object_entry_separator<Opts>(ctx, args...);
1134
+ }
1135
+ else {
1136
+ auto write_first_entry = [&](auto && it) {
1137
+ auto && [key, entry_val] = *it;
1138
+ write_pair_content<Opts>(key, entry_val, ctx, b, ix);
1139
+ };
1140
+
1141
+ auto it = std::begin (value);
1142
+ write_first_entry (it);
1143
+ ++it;
1144
+ for (const auto end = std::end (value); it != end; ++it) {
1145
+ auto && [key, entry_val] = *it;
1146
+ write_object_entry_separator<Opts>(ctx, b, ix);
1147
+ write_pair_content<Opts>(key, entry_val, ctx, b, ix);
1119
1148
}
1120
-
1121
- write_pair_content<Opts>(key, entry_val, ctx, args...);
1122
1149
}
1123
-
1124
- starting = false ;
1125
1150
}
1126
1151
1127
1152
if constexpr (!has_closing_handled (Opts)) {
1128
1153
if constexpr (Opts.prettify ) {
1129
1154
ctx.indentation_level -= Opts.indentation_width ;
1130
- dump_newline_indent<Opts.indentation_char >(ctx.indentation_level , args...);
1155
+ if constexpr (vector_like<B>) {
1156
+ if (const auto k = ix + ctx.indentation_level + write_padding_bytes; k > b.size ()) [[unlikely]] {
1157
+ b.resize (2 * k);
1158
+ }
1159
+ }
1160
+ std::memcpy (&b[ix], " \n " , 1 );
1161
+ ++ix;
1162
+ std::memset (&b[ix], Opts.indentation_char , ctx.indentation_level );
1163
+ ix += ctx.indentation_level ;
1131
1164
}
1132
1165
}
1133
1166
}
1134
1167
1135
1168
if constexpr (!has_closing_handled (Opts)) {
1136
- dump<' }' >(args... );
1169
+ dump<' }' >(b, ix );
1137
1170
}
1138
1171
}
1139
1172
};
0 commit comments