Skip to content

Commit 1642291

Browse files
authored
perf: reduce allocations in sorting pipeline (#65)
1 parent 4a18956 commit 1642291

File tree

1 file changed

+39
-41
lines changed

1 file changed

+39
-41
lines changed

src/lib.rs

Lines changed: 39 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -148,26 +148,24 @@ fn transform_with_key_order(value: Value, key_order: &[&str]) -> Value {
148148
transform_value(value, |o| sort_object_by_key_order(o, key_order))
149149
}
150150

151-
fn sort_object_alphabetically(obj: Map<String, Value>) -> Map<String, Value> {
152-
let mut entries: Vec<(String, Value)> = obj.into_iter().collect();
153-
entries.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
154-
entries.into_iter().collect()
151+
fn sort_object_alphabetically(mut obj: Map<String, Value>) -> Map<String, Value> {
152+
obj.sort_keys();
153+
obj
155154
}
156155

157156
fn sort_object_recursive(obj: Map<String, Value>) -> Map<String, Value> {
158-
let mut entries: Vec<(String, Value)> = obj.into_iter().collect();
159-
entries.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
160-
161-
entries
162-
.into_iter()
163-
.map(|(key, value)| {
164-
let transformed_value = match value {
165-
Value::Object(nested) => Value::Object(sort_object_recursive(nested)),
166-
_ => value,
167-
};
168-
(key, transformed_value)
169-
})
170-
.collect()
157+
let mut obj = obj;
158+
sort_object_recursive_in_place(&mut obj);
159+
obj
160+
}
161+
162+
fn sort_object_recursive_in_place(obj: &mut Map<String, Value>) {
163+
for value in obj.values_mut() {
164+
if let Value::Object(nested) = value {
165+
sort_object_recursive_in_place(nested);
166+
}
167+
}
168+
obj.sort_keys();
171169
}
172170

173171
fn sort_array_unique(mut arr: Vec<Value>) -> Vec<Value> {
@@ -185,40 +183,39 @@ fn sort_array_unique(mut arr: Vec<Value>) -> Vec<Value> {
185183

186184
/// Deduplicate array while preserving order (no sorting).
187185
/// Used for fields where order matters (e.g., `files` with `!` negation patterns).
188-
fn dedupe_array(arr: Vec<Value>) -> Vec<Value> {
189-
let mut seen: Vec<&str> = Vec::new();
190-
let keep: Vec<bool> = arr
191-
.iter()
192-
.map(|v| {
193-
v.as_str().is_some_and(|s| {
194-
if seen.contains(&s) {
195-
false
196-
} else {
197-
seen.push(s);
198-
true
199-
}
200-
})
201-
})
202-
.collect();
203-
arr.into_iter().zip(keep).filter_map(|(v, keep)| keep.then_some(v)).collect()
186+
fn dedupe_array(mut arr: Vec<Value>) -> Vec<Value> {
187+
let mut write = 0;
188+
for read in 0..arr.len() {
189+
let keep = match arr[read].as_str() {
190+
Some(s) => !arr[..write].iter().any(|seen| seen.as_str() == Some(s)),
191+
None => false,
192+
};
193+
if keep {
194+
if write != read {
195+
arr.swap(write, read);
196+
}
197+
write += 1;
198+
}
199+
}
200+
arr.truncate(write);
201+
arr
204202
}
205203

206204
fn sort_object_by_key_order(mut obj: Map<String, Value>, key_order: &[&str]) -> Map<String, Value> {
205+
obj.sort_keys();
206+
207207
// Pre-allocate capacity to avoid reallocations
208208
let mut result = Map::with_capacity(obj.len());
209209

210210
// Add keys in specified order
211211
for &key in key_order {
212-
if let Some(value) = obj.remove(key) {
212+
if let Some(value) = obj.shift_remove(key) {
213213
result.insert(key.into(), value);
214214
}
215215
}
216216

217-
// Add remaining keys alphabetically
218-
let mut remaining: Vec<(String, Value)> = obj.into_iter().collect();
219-
remaining.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
220-
221-
for (key, value) in remaining {
217+
// Remaining keys are already sorted alphabetically.
218+
for (key, value) in obj {
222219
result.insert(key, value);
223220
}
224221

@@ -230,6 +227,7 @@ fn sort_people_object(obj: Map<String, Value>) -> Map<String, Value> {
230227
}
231228

232229
fn sort_exports(obj: Map<String, Value>) -> Map<String, Value> {
230+
let obj_len = obj.len();
233231
let mut paths = Vec::new();
234232
let mut types_conds = Vec::new();
235233
let mut other_conds = Vec::new();
@@ -247,7 +245,7 @@ fn sort_exports(obj: Map<String, Value>) -> Map<String, Value> {
247245
}
248246
}
249247

250-
let mut result = Map::new();
248+
let mut result = Map::with_capacity(obj_len);
251249

252250
// Add in order: paths, types, others, default
253251
for (key, value) in paths {
@@ -454,7 +452,7 @@ fn sort_object_keys(obj: Map<String, Value>, options: &SortOptions) -> Map<Strin
454452
private.sort_unstable_by(|(a, _), (b, _)| a.cmp(b));
455453

456454
// Build result map
457-
let mut result = Map::new();
455+
let mut result = Map::with_capacity(known.len() + non_private.len() + private.len());
458456

459457
// Insert known fields (already transformed)
460458
for (_index, key, value) in known {

0 commit comments

Comments
 (0)