@@ -843,6 +843,27 @@ 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 IteratorValue = iterator_pair_type<Container>>
851
+ struct iterator_value_impl ;
852
+
853
+ template <class Container , typename IteratorValue>
854
+ requires has_value_type<IteratorValue>
855
+ struct iterator_value_impl <Container, IteratorValue> {
856
+ using type = typename IteratorValue::value_type;
857
+ };
858
+
859
+ template <class Container , typename IteratorValue>
860
+ requires (!has_value_type<IteratorValue> && has_second_type<IteratorValue>)
861
+ struct iterator_value_impl<Container, IteratorValue> {
862
+ using type = typename IteratorValue::second_type;
863
+ };
864
+
865
+ template <class Container >
866
+ using iterator_value_type = typename iterator_value_impl<Container>::type;
846
867
847
868
template <class T >
848
869
requires (writable_array_t <T> || writable_map_t <T>)
@@ -1056,80 +1077,121 @@ namespace glz
1056
1077
ix += ctx.indentation_level ;
1057
1078
}
1058
1079
}
1080
+
1081
+ using val_t = iterator_value_type<T>; // the type of value in each [key, value] pair
1082
+
1083
+ if constexpr (not always_skipped<val_t >)
1084
+ {
1085
+ if constexpr (null_t <val_t >)
1086
+ {
1087
+ auto write_first_entry = [&ctx, &b, &ix](auto && it) {
1088
+ if constexpr (requires {
1089
+ it->first ;
1090
+ it->second ;
1091
+ }) {
1092
+ // Allow non-const access, unlike ranges
1093
+ if (skip_member<Opts>(it->second )) {
1094
+ return true ;
1095
+ }
1096
+ write_pair_content<Opts>(it->first , it->second , ctx, b, ix);
1097
+ return false ;
1098
+ }
1099
+ else {
1100
+ const auto & [key, entry_val] = *it;
1101
+ if (skip_member<Opts>(entry_val)) {
1102
+ return true ;
1103
+ }
1104
+ write_pair_content<Opts>(key, entry_val, ctx, b, ix);
1105
+ return false ;
1106
+ }
1107
+ };
1108
+
1109
+ auto it = std::begin (value);
1110
+ [[maybe_unused]] bool starting = write_first_entry (it);
1111
+ ++it;
1112
+ for (const auto end = std::end (value); it != end; ++it) {
1113
+ // I couldn't find an easy way around this code duplication
1114
+ // Ranges need to be decomposed with const auto& [...],
1115
+ // but we don't want to const qualify our maps for the sake of reflection writing
1116
+ // we need to be able to populate the tuple of pointers when writing with reflection
1117
+ if constexpr (requires {
1118
+ it->first ;
1119
+ it->second ;
1120
+ }) {
1121
+ if (skip_member<Opts>(it->second )) {
1122
+ continue ;
1123
+ }
1059
1124
1060
- auto write_first_entry = [&ctx, &b, &ix](auto && it) {
1061
- if constexpr (requires {
1062
- it->first ;
1063
- it->second ;
1064
- }) {
1065
- // Allow non-const access, unlike ranges
1066
- if (skip_member<Opts>(it->second )) {
1067
- return true ;
1068
- }
1069
- write_pair_content<Opts>(it->first , it->second , ctx, b, ix);
1070
- return false ;
1071
- }
1072
- else {
1073
- const auto & [key, entry_val] = *it;
1074
- if (skip_member<Opts>(entry_val)) {
1075
- return true ;
1076
- }
1077
- write_pair_content<Opts>(key, entry_val, ctx, b, ix);
1078
- return false ;
1079
- }
1080
- };
1081
-
1082
- auto it = std::begin (value);
1083
- [[maybe_unused]] bool starting = write_first_entry (it);
1084
- for (++it; it != std::end (value); ++it) {
1085
- // I couldn't find an easy way around this code duplication
1086
- // Ranges need to be decomposed with const auto& [...],
1087
- // but we don't want to const qualify our maps for the sake of reflection writing
1088
- // we need to be able to populate the tuple of pointers when writing with reflection
1089
- if constexpr (requires {
1090
- it->first ;
1091
- it->second ;
1092
- }) {
1093
- if (skip_member<Opts>(it->second )) {
1094
- continue ;
1095
- }
1125
+ // When Opts.skip_null_members, *any* entry may be skipped, meaning separator dumping must be
1126
+ // conditional for every entry. Avoid this branch when not skipping null members.
1127
+ // Alternatively, write separator after each entry except last but then branch is permanent
1128
+ if constexpr (Opts.skip_null_members ) {
1129
+ if (!starting) {
1130
+ write_object_entry_separator<Opts>(ctx, b, ix);
1131
+ }
1132
+ }
1133
+ else {
1134
+ write_object_entry_separator<Opts>(ctx, b, ix);
1135
+ }
1096
1136
1097
- // When Opts.skip_null_members, *any* entry may be skipped, meaning separator dumping must be
1098
- // conditional for every entry. Avoid this branch when not skipping null members.
1099
- // Alternatively, write separator after each entry except last but then branch is permanent
1100
- if constexpr (Opts.skip_null_members ) {
1101
- if (!starting) {
1102
- write_object_entry_separator<Opts>(ctx, b, ix);
1137
+ write_pair_content<Opts>(it->first , it->second , ctx, b, ix);
1103
1138
}
1104
- }
1105
- else {
1106
- write_object_entry_separator<Opts>(ctx, b, ix);
1107
- }
1139
+ else {
1140
+ const auto & [key, entry_val] = *it;
1141
+ if (skip_member<Opts>(entry_val)) {
1142
+ continue ;
1143
+ }
1108
1144
1109
- write_pair_content<Opts>(it->first , it->second , ctx, b, ix);
1145
+ // When Opts.skip_null_members, *any* entry may be skipped, meaning separator dumping must be
1146
+ // conditional for every entry. Avoid this branch when not skipping null members.
1147
+ // Alternatively, write separator after each entry except last but then branch is permanent
1148
+ if constexpr (Opts.skip_null_members ) {
1149
+ if (!starting) {
1150
+ write_object_entry_separator<Opts>(ctx, b, ix);
1151
+ }
1152
+ }
1153
+ else {
1154
+ write_object_entry_separator<Opts>(ctx, b, ix);
1155
+ }
1156
+
1157
+ write_pair_content<Opts>(key, entry_val, ctx, b, ix);
1158
+ }
1159
+
1160
+ starting = false ;
1161
+ }
1110
1162
}
1111
1163
else {
1112
- const auto & [key, entry_val] = *it;
1113
- if (skip_member<Opts>(entry_val)) {
1114
- continue ;
1115
- }
1116
-
1117
- // When Opts.skip_null_members, *any* entry may be skipped, meaning separator dumping must be
1118
- // conditional for every entry. Avoid this branch when not skipping null members.
1119
- // Alternatively, write separator after each entry except last but then branch is permanent
1120
- if constexpr (Opts.skip_null_members ) {
1121
- if (!starting) {
1164
+ auto write_first_entry = [&ctx, &b, &ix](auto && it) {
1165
+ if constexpr (requires {
1166
+ it->first ;
1167
+ it->second ;
1168
+ }) {
1169
+ write_pair_content<Opts>(it->first , it->second , ctx, b, ix);
1170
+ }
1171
+ else {
1172
+ const auto & [key, entry_val] = *it;
1173
+ write_pair_content<Opts>(key, entry_val, ctx, b, ix);
1174
+ }
1175
+ };
1176
+
1177
+ auto it = std::begin (value);
1178
+ write_first_entry (it);
1179
+ ++it;
1180
+ for (const auto end = std::end (value); it != end; ++it) {
1181
+ if constexpr (requires {
1182
+ it->first ;
1183
+ it->second ;
1184
+ }) {
1122
1185
write_object_entry_separator<Opts>(ctx, b, ix);
1186
+ write_pair_content<Opts>(it->first , it->second , ctx, b, ix);
1187
+ }
1188
+ else {
1189
+ const auto & [key, entry_val] = *it;
1190
+ write_object_entry_separator<Opts>(ctx, b, ix);
1191
+ write_pair_content<Opts>(key, entry_val, ctx, b, ix);
1123
1192
}
1124
1193
}
1125
- else {
1126
- write_object_entry_separator<Opts>(ctx, b, ix);
1127
- }
1128
-
1129
- write_pair_content<Opts>(key, entry_val, ctx, b, ix);
1130
1194
}
1131
-
1132
- starting = false ;
1133
1195
}
1134
1196
1135
1197
if constexpr (!has_closing_handled (Opts)) {
0 commit comments