From 226d3aa6c5416c46db9d16c9c3732431372c2d9a Mon Sep 17 00:00:00 2001 From: Лач Date: Sun, 19 Jul 2020 14:50:40 +0000 Subject: [PATCH] perf: faster sort --- --- a/crates/jrsonnet-evaluator/build.rs +++ b/crates/jrsonnet-evaluator/build.rs @@ -38,7 +38,8 @@ }) if **name == *"join" || **name == *"manifestJsonEx" || **name == *"escapeStringJson" || **name == *"equals" || - **name == *"base64" || **name == *"foldl" || **name == *"foldr" + **name == *"base64" || **name == *"foldl" || **name == *"foldr" || + **name == *"sortImpl" ) }) .collect(), --- a/crates/jrsonnet-evaluator/src/evaluate.rs +++ b/crates/jrsonnet-evaluator/src/evaluate.rs @@ -10,7 +10,7 @@ ForSpecData, IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc, UnaryOpType, Visibility, }; -use std::{collections::HashMap, rc::Rc}; +use std::{cmp::Ordering, collections::HashMap, rc::Rc}; pub fn evaluate_binding(b: &BindSpec, context_creator: ContextCreator) -> (Rc, LazyBinding) { let b = b.clone(); @@ -581,6 +581,58 @@ } Ok(acc) }))?, + // faster + ("std", "sortImpl") => noinline!(parse_args!(context, "std.sort", args, 2, [ + 0, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr]; + 1, keyF: [Val::Func]!!Val::Func, vec![ValType::Func]; + ], { + if arr.len() <= 1 { + return Ok(Val::Arr(arr)) + } + let mut new_arr = arr.iter().cloned().collect::>(); + match keyF.evaluate_values(context.clone(), &[new_arr[0].clone()])? { + Val::Str(_) => { + let mut err = None; + new_arr.sort_by_cached_key(|k| { + match keyF.evaluate_values(context.clone(), &[k.clone()]) { + Ok(Val::Str(v)) => v, + Ok(_) => { + err = Some(create_error(crate::error::Error::RuntimeError("types of all array elements should equal".into()))); + "".into() + } + Err(e) => { + err = Some(e); + "".into() + } + } + }); + if let Some(e) = err { + return Err(e); + } + }, + Val::Num(_) => { + let mut err = None; + new_arr.sort_unstable_by(|a, b| { + match (keyF.evaluate_values(context.clone(), &[a.clone()]), keyF.evaluate_values(context.clone(), &[b.clone()])) { + (Ok(Val::Num(a)), Ok(Val::Num(b))) => a.partial_cmp(&b).unwrap(), + (Ok(_a), Ok(_b)) => { + err = Some(create_error(crate::error::Error::RuntimeError("types of all array elements should equal".into()))); + Ordering::Equal + } + (Err(e), _) | (_, Err(e)) => { + err = Some(e); + Ordering::Equal + } + } + }); + if let Some(e) = err { + return Err(e); + } + }, + _ => return Err(create_error(crate::error::Error::RuntimeError("keys should be number or string".into()))) + } + Ok(Val::Arr(Rc::new(new_arr))) + }))?, ("std", "char") => parse_args!(context, "std.char", args, 1, [ 0, n: [Val::Num]!!Val::Num, vec![ValType::Num]; ], { --- a/crates/jrsonnet-stdlib/src/std.jsonnet +++ b/crates/jrsonnet-stdlib/src/std.jsonnet @@ -1131,7 +1131,7 @@ std.makeArray(l, function(i) arr[l - i - 1]), // Merge-sort for long arrays and naive quicksort for shorter ones - sort(arr, keyF=id):: + sortImpl(arr, keyF):: local quickSort(arr, keyF=id) = local l = std.length(arr); if std.length(arr) <= 1 then @@ -1166,6 +1166,9 @@ local left = arr[:mid], right = arr[mid:]; merge(std.sort(left, keyF=keyF), std.sort(right, keyF=keyF)), + sort(arr, keyF=id):: + std.sortImpl(arr, keyF), + uniq(arr, keyF=id):: local f(a, b) = if std.length(a) == 0 then -- gitstuff