sort n rand

This commit is contained in:
Freya Murphy 2024-02-26 20:39:39 -05:00
parent 158bcae00d
commit 4438116264
Signed by: freya
GPG key ID: 744AB800E383AE52
5 changed files with 181 additions and 8 deletions

54
Cargo.lock generated
View file

@ -181,6 +181,17 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "getrandom"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "heck"
version = "0.4.1"
@ -251,6 +262,7 @@ dependencies = [
"anyhow",
"matrix",
"matrix-macros",
"rand",
]
[[package]]
@ -329,6 +341,12 @@ dependencies = [
"autocfg",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.78"
@ -357,6 +375,36 @@ dependencies = [
"nibble_vec",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "regex"
version = "1.10.3"
@ -491,6 +539,12 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"

View file

@ -9,3 +9,4 @@ edition = "2021"
anyhow = "1"
matrix = { path = "../matrix" }
matrix-macros = { path = "../matrix-macros" }
rand = "0.8"

View file

@ -2,7 +2,8 @@ use std::hash::{DefaultHasher, Hash, Hasher};
use matrix::{vm::Vm, value::Value, unpack_args, Result, unpack_varargs};
use matrix_macros::native_func;
use crate::{VmArgs, error};
use rand::Rng;
use crate::{VmArgs, next, error};
fn to_radix(r: i64, mut n: i64) -> String {
@ -162,6 +163,116 @@ fn str(_: VmArgs, args: Vec<Value>) -> Result<Value> {
Ok(Value::String(format!("{value}").into()))
}
fn partition(list: &mut [Value], lo: usize, hi: usize) -> (usize, usize) {
let pivot = list[(lo + hi) / 2].clone();
let mut lt = lo;
let mut eq = lo;
let mut gt = hi;
while eq <= gt {
if list[eq] < pivot {
list.swap(eq, lt);
lt += 1;
eq += 1;
} else if list[eq] > pivot {
list.swap(eq, gt);
gt -= 1;
} else {
eq += 1;
}
}
(lt, gt)
}
fn quicksort(list: &mut [Value], lo: usize, hi: usize) {
if lo < hi {
let (lt, gt) = partition(list, lo, hi);
if lt > 0 {
quicksort(list, lo, lt - 1);
}
quicksort(list, gt + 1, hi);
}
}
#[native_func(1)]
fn sort(_: VmArgs, args: Vec<Value>) -> Result<Value> {
let [value] = unpack_args!(args);
let Value::List(mut list) = value else {
return error!("sort requires a list")
};
let hi = list.len() - 1;
quicksort(list.as_mut(), 0, hi);
Ok(Value::List(list))
}
#[native_func(0)]
fn rand(_: VmArgs, _: Vec<Value>) -> Result<Value> {
let mut rng = rand::thread_rng();
Ok(Value::Float(rng.gen()))
}
#[native_func(0..)]
fn rand_range(_: VmArgs, args: Vec<Value>) -> Result<Value> {
use Value as V;
let ([], varargs) = unpack_varargs!(args);
let (min, max, step) = match varargs.as_slice() {
[V::Int(max)] => {
(0, *max, 1)
},
[V::Int(min), V::Int(max)] => {
(*min, *max, 1)
},
[V::Int(min), V::Int(max), V::Int(step)] => {
(*min, *max, *step)
},
_ => return error!("rand_range takes 1 to 3 [Int]'s")
};
if max <= min {
return Ok(Value::Int(min))
}
let count = ((max - 1 - min) / step) + 1;
let rng = (rand::thread_rng().gen::<u32>() % (count as u32)) as i64;
let i = min + (rng * step);
Ok(Value::Int(i))
}
#[native_func(2)]
fn rand_int(_: VmArgs, args: Vec<Value>) -> Result<Value> {
use Value as V;
let (min, max) = match args.as_slice() {
[V::Int(min), V::Int(max)] => {
(*min, *max + 1)
},
_ => return error!("rand_int takes 2 [Int]'s")
};
if max <= min {
return Ok(Value::Int(min))
}
let count = max - min;
let rng = (rand::thread_rng().gen::<u32>() % (count as u32)) as i64;
let i = min + rng;
Ok(Value::Int(i))
}
#[native_func(1)]
fn rand_in((vm, frame): VmArgs, args: Vec<Value>) -> Result<Value> {
let [iter] = unpack_args!(args);
let iter = iter.into_iter_fn()?;
let mut vals = Vec::new();
loop {
let val = next!(vm, frame, iter)?;
if val == Value::Nil { break }
vals.push(val);
}
if vals.is_empty() {
return Ok(Value::Nil)
}
let idx = rand::thread_rng().gen::<usize>() % vals.len();
Ok(vals[idx].clone())
}
pub fn load(vm: &mut Vm) {
vm.load_global_fn(bin(), "bin");
vm.load_global_fn(sex(), "sex");
@ -178,4 +289,10 @@ pub fn load(vm: &mut Vm) {
vm.load_global_fn(hash(), "hash");
vm.load_global_fn(ord(), "ord");
vm.load_global_fn(chr(), "chr");
vm.load_global_fn(sort(), "sort");
vm.load_global_fn(rand(), "rand");
vm.load_global_fn(rand_range(), "rand_range");
vm.load_global_fn(rand_int(), "rand_int");
vm.load_global_fn(rand_in(), "rand_in");
}

View file

@ -1,16 +1,10 @@
use std::{cell::RefCell, rc::Rc};
use matrix::{iter, vm::Vm, value::Value, Result, unpack_varargs, unpack_args};
use matrix_macros::native_func;
use crate::{error, VmArgs};
use crate::{error, next, VmArgs};
use Value as V;
macro_rules! next {
($vm:expr, $frame:expr, $iter:expr) => {
$vm.run_fn($frame, $iter.clone(), vec![])
};
}
#[native_func(1)]
fn len(_: VmArgs, args: Vec<Value>) -> Result<Value> {
let [value] = unpack_args!(args);

View file

@ -14,7 +14,14 @@ macro_rules! error {
};
}
macro_rules! next {
($vm:expr, $frame:expr, $iter:expr) => {
$vm.run_fn($frame, $iter.clone(), vec![])
};
}
pub(crate) use error;
pub(crate) use next;
pub fn load(vm: &mut Vm) {
core::load(vm);