mirror of
https://github.com/javalsai/aoc.git
synced 2026-01-12 17:10:00 +01:00
add: d05 & debug utils
- includes a script to generate a 2GB big challenge - added utils to internally time functions with minimal overhead - add functionality to tester.rs
This commit is contained in:
22
2025/05/gen.py
Normal file
22
2025/05/gen.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import random
|
||||
|
||||
MAX=(2**64)-1
|
||||
RANGES=1000000
|
||||
IDS=100000000
|
||||
|
||||
list_of_ids = []
|
||||
|
||||
with open('2025-huge.txt', 'a') as file:
|
||||
for x in range(1000):
|
||||
num1 = random.randint(1, MAX)
|
||||
num2 = random.randint(1, MAX)
|
||||
if num1 > num2:
|
||||
tmp = num1
|
||||
num1 = num2
|
||||
num2 = tmp
|
||||
file.write(f'{num1}-{num2}\n')
|
||||
file.write('\n')
|
||||
for x in range(IDS):
|
||||
num = random.randint(2, MAX-1)
|
||||
if not (num in list_of_ids):
|
||||
file.write(f'{num}\n')
|
||||
218
2025/05/p1-opt.rs
Normal file
218
2025/05/p1-opt.rs
Normal file
@@ -0,0 +1,218 @@
|
||||
#[unsafe(no_mangle)]
|
||||
pub static mut TIMERS: [(&str, Duration); TIMERS_LEN] = [
|
||||
("insert", Duration::ZERO),
|
||||
("count", Duration::ZERO),
|
||||
];
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub static TIMERS_LEN: usize = 2;
|
||||
use std::{ops::RangeInclusive, time::{Duration, Instant}};
|
||||
|
||||
pub type RangeU = u128;
|
||||
|
||||
pub struct BIntervalNode<T: Ord + Copy> {
|
||||
value: RangeInclusive<T>,
|
||||
len: usize,
|
||||
lt: Option<Box<BIntervalNode<T>>>,
|
||||
gt: Option<Box<BIntervalNode<T>>>,
|
||||
}
|
||||
|
||||
impl<T: Ord + Copy> BIntervalNode<T> {
|
||||
pub fn new(value: RangeInclusive<T>) -> Self {
|
||||
Self {
|
||||
value,
|
||||
len: 1,
|
||||
lt: None,
|
||||
gt: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn _is_gt_non_overlapping(lhs: &RangeInclusive<T>, rhs: &RangeInclusive<T>) -> bool {
|
||||
rhs.start() > lhs.start()
|
||||
}
|
||||
|
||||
pub fn _overlap_with(&self, value: &RangeInclusive<T>) -> RangeInclusive<T> {
|
||||
(*self.value.start().min(value.start()))..=(*self.value.end().max(value.end()))
|
||||
}
|
||||
|
||||
pub fn _overlap(&self, value: &RangeInclusive<T>) -> bool {
|
||||
(value.start() <= self.value.start() && value.end() >= self.value.start())
|
||||
|| (value.end() >= self.value.end() && value.start() <= self.value.end())
|
||||
}
|
||||
|
||||
pub fn _get_which(&mut self, which: bool) -> &mut Option<Box<Self>> {
|
||||
if which { &mut self.gt } else { &mut self.lt }
|
||||
}
|
||||
|
||||
/// See [`Self::_swap_ptrs_with()`] for the ptr swap, now lenths.
|
||||
///
|
||||
/// self self
|
||||
/// (A) (B)
|
||||
/// (B) C --> D (A)
|
||||
/// D E E C
|
||||
///
|
||||
/// stays the same: C, D, E
|
||||
/// A = B + C; B = D + E (C = A - B)
|
||||
/// A = E + C; B = D + A
|
||||
///
|
||||
/// B' = B - E + A' = A
|
||||
/// A' = A - B + E
|
||||
pub fn _swap_with(self: &mut Box<Self>, which: bool) {
|
||||
unsafe fn copy_mut<'a, T>(mutref: *mut T) -> &'a mut T {
|
||||
unsafe { &mut *mutref }
|
||||
}
|
||||
|
||||
let total_len = self.len;
|
||||
let e_len = self._swap_ptrs_with(which);
|
||||
// SAFETY: its different fields
|
||||
let sub = unsafe { copy_mut(self._get_which(which).as_mut().unwrap()) };
|
||||
|
||||
self.len -= sub.len + e_len;
|
||||
sub.len = total_len;
|
||||
}
|
||||
|
||||
/// True if the gt one, false if lt
|
||||
///
|
||||
/// self self
|
||||
/// (A) (B)
|
||||
/// a b x y
|
||||
/// (B) C --> D (A)
|
||||
/// x y a b
|
||||
/// D E E C
|
||||
///
|
||||
/// `self` here is the **pointer to the pointer** to the root element
|
||||
/// a = &E (y)
|
||||
/// y = &A (self)
|
||||
/// self = B (a)
|
||||
///
|
||||
/// also returns `E`s length if existent or 0
|
||||
pub fn _swap_ptrs_with(self: &mut Box<Self>, which: bool) -> usize {
|
||||
unsafe fn copy<T>(optbox: &T) -> T {
|
||||
unsafe { std::mem::transmute_copy::<_, T>(optbox) }
|
||||
}
|
||||
unsafe fn copy_mut<'a, T>(mutref: *mut T) -> &'a mut T {
|
||||
unsafe { &mut *mutref }
|
||||
}
|
||||
|
||||
// SAFETY: we clone the mut ptr to separate their lifetime relation, its fine as long as we
|
||||
// dont walk into the `&mut Option<...>`s (`lt` and `gt` field ptrs) and treat it only as
|
||||
// the node field's ptr to be updated
|
||||
let my_sub_field_ptr = unsafe { copy_mut(self._get_which(which)) }; // a
|
||||
let my_sub_ptr = unsafe { copy_mut(my_sub_field_ptr.as_mut().unwrap()) }; // B
|
||||
let my_subs_other_sub_field_ptr = unsafe { copy_mut(my_sub_ptr._get_which(!which)) }; // y
|
||||
|
||||
// SAFETY: Copied because it can't move out as the original location must remain valid.
|
||||
// However this is a triangular rotation and the final place will end up being replaced
|
||||
// too, so this is safe.
|
||||
*my_sub_field_ptr = unsafe { copy(my_subs_other_sub_field_ptr) };
|
||||
*my_subs_other_sub_field_ptr = Some(unsafe { copy(self) });
|
||||
*self = unsafe { copy(my_sub_ptr) };
|
||||
|
||||
my_sub_field_ptr.as_ref().map(|n| n.len).unwrap_or(0)
|
||||
}
|
||||
|
||||
/// Returns `true` if the len count has grown somewhere down the line
|
||||
pub fn _insert(self: &mut Box<Self>, value: RangeInclusive<T>) -> bool {
|
||||
if self._overlap(&value) {
|
||||
self.value = self._overlap_with(&value);
|
||||
return false;
|
||||
}
|
||||
|
||||
let is_gt = Self::_is_gt_non_overlapping(&self.value, &value);
|
||||
let next_node: &mut _ = if is_gt { &mut self.gt } else { &mut self.lt };
|
||||
|
||||
if let Some(next_node) = next_node {
|
||||
let inserted = next_node._insert(value);
|
||||
if inserted {
|
||||
self.len += 1;
|
||||
}
|
||||
|
||||
// first of all, do we balance?
|
||||
// maybe >= 2 will balance more but itd be too unstable, TODO play with constant
|
||||
if (self.len + 1) / (next_node.len + 1) > 2 {
|
||||
// self._swap_with(is_gt);
|
||||
}
|
||||
|
||||
inserted
|
||||
} else {
|
||||
*next_node = Some(Box::new(Self::new(value)));
|
||||
self.len += 1;
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(self: &mut Box<Self>, value: RangeInclusive<T>) {
|
||||
self._insert(value);
|
||||
}
|
||||
|
||||
pub fn contains(&self, value: &T) -> bool {
|
||||
if self.value.start() > value {
|
||||
self.lt.as_ref().is_some_and(|lt| lt.contains(value))
|
||||
} else if self.value.end() < value {
|
||||
self.gt.as_ref().is_some_and(|gt| gt.contains(value))
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct BIntervalTree<T: Ord + Copy> {
|
||||
first_node: Box<BIntervalNode<T>>,
|
||||
}
|
||||
|
||||
impl<T: Ord + Copy> BIntervalTree<T> {
|
||||
fn insert(&mut self, value: RangeInclusive<T>) {
|
||||
self.first_node.insert(value);
|
||||
}
|
||||
|
||||
fn contains(&self, value: &T) -> bool {
|
||||
self.first_node.contains(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Ord + Copy> FromIterator<RangeInclusive<A>> for BIntervalTree<A> {
|
||||
/// # Panic
|
||||
///
|
||||
/// Must not be an empty iterator (this is not design I just want perf on this)
|
||||
fn from_iter<T: IntoIterator<Item = RangeInclusive<A>>>(iter: T) -> Self {
|
||||
let mut iter = iter.into_iter();
|
||||
let mut myself = Self {
|
||||
first_node: Box::new(BIntervalNode::new(iter.next().unwrap())),
|
||||
};
|
||||
|
||||
for range in iter {
|
||||
myself.insert(range);
|
||||
}
|
||||
myself
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "Rust" fn challenge_t_usize(buf: &[u8], t: &Instant) -> usize {
|
||||
let s = unsafe { str::from_utf8_unchecked(buf) };
|
||||
let mut lines = s.lines();
|
||||
|
||||
let mut count = 0;
|
||||
|
||||
let ran_iter = (&mut lines).take_while(|ln| !ln.is_empty()).map(|range| {
|
||||
let (l, r) = range.split_once('-').unwrap();
|
||||
let (l, r) = (l.parse().unwrap(), r.parse().unwrap());
|
||||
l..=r
|
||||
});
|
||||
|
||||
let ranges = BIntervalTree::<RangeU>::from_iter(ran_iter);
|
||||
|
||||
unsafe { TIMERS[0].1 = t.elapsed() };
|
||||
|
||||
for id in lines {
|
||||
let id: RangeU = id.parse().unwrap();
|
||||
|
||||
if ranges.contains(&id) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { TIMERS[1].1 = t.elapsed() };
|
||||
|
||||
count
|
||||
}
|
||||
88
2025/05/p1-opt3.rs
Normal file
88
2025/05/p1-opt3.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
pub type RangeU = u128;
|
||||
pub type NestingCountT = i16;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub static mut TIMERS: [(&str, Duration); TIMERS_LEN] = [
|
||||
("after-parse", Duration::ZERO),
|
||||
("flatten-vec", Duration::ZERO),
|
||||
("count-ids", Duration::ZERO),
|
||||
];
|
||||
#[unsafe(no_mangle)]
|
||||
pub static TIMERS_LEN: usize = 3;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "Rust" fn challenge_t_usize(buf: &[u8], t: &Instant) -> usize {
|
||||
let mut count = 0;
|
||||
let s = unsafe { str::from_utf8_unchecked(buf) };
|
||||
let mut lines = s.lines();
|
||||
|
||||
let mut bmap = BTreeMap::<_, NestingCountT>::new();
|
||||
|
||||
(&mut lines)
|
||||
.take_while(|ln| !ln.is_empty())
|
||||
.for_each(|range| {
|
||||
let (l, r) = range.split_once('-').unwrap();
|
||||
let (l, r) = (l.parse().unwrap(), r.parse().unwrap());
|
||||
|
||||
bmap.entry(l).and_modify(|k| *k += 1).or_insert(1);
|
||||
bmap.entry(r).and_modify(|k| *k -= 1).or_insert(-1);
|
||||
});
|
||||
|
||||
unsafe { TIMERS[0].1 = t.elapsed() };
|
||||
|
||||
let mut arr = Vec::with_capacity(size_of::<bool>() * bmap.len());
|
||||
// I could directly search on the btree, but I feel flattening at once and then searching can
|
||||
// speed up things bcs continuity indirection and stuff. It also makes it easier to iterate at
|
||||
// once. This would be O(n) and the latter access in O(log n) (O(n log n) bcs it iterates for
|
||||
// each id)
|
||||
let mut last_pushed = false;
|
||||
let mut nested_ran_acc = 0;
|
||||
for (idx, nesting) in bmap {
|
||||
nested_ran_acc += nesting;
|
||||
if last_pushed != (nested_ran_acc > 0) {
|
||||
last_pushed = !last_pushed;
|
||||
arr.push((idx, last_pushed));
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { TIMERS[1].1 = t.elapsed() };
|
||||
|
||||
let all_ranges_bounds = (arr[0].0, arr[arr.len() - 1].0);
|
||||
for id in lines {
|
||||
let id: RangeU = id.parse().unwrap();
|
||||
if id < all_ranges_bounds.0 || id > all_ranges_bounds.1 {
|
||||
continue;
|
||||
}
|
||||
|
||||
// let idx = arr.binary_search_by_key(&id, |p| p.0).err(|i| i);
|
||||
// let is_in_any_range = arr.get(idx).map(|p| p.1).unwrap();
|
||||
let is_in_any_range = binary_search_inclusive_or_lower_bound(&arr, id);
|
||||
|
||||
if is_in_any_range {
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { TIMERS[2].1 = t.elapsed() };
|
||||
|
||||
count
|
||||
}
|
||||
|
||||
fn binary_search_inclusive_or_lower_bound(arr: &[(RangeU, bool)], id: RangeU) -> bool {
|
||||
let all_ranges_bounds = (arr[0].0, arr[arr.len() - 1].0);
|
||||
|
||||
if id < all_ranges_bounds.0 || id > all_ranges_bounds.1 {
|
||||
return false;
|
||||
}
|
||||
|
||||
match arr.binary_search_by_key(&id, |p| p.0) {
|
||||
Ok(_) => true, // the rising edge is true and if falling edge its false but included so
|
||||
// should get truthed. In general if its found it was an edge so return true
|
||||
Err(idx) => arr[idx - 1].1,
|
||||
}
|
||||
}
|
||||
51
2025/05/p1.rs
Normal file
51
2025/05/p1.rs
Normal file
@@ -0,0 +1,51 @@
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub static mut TIMERS: [(&str, Duration); TIMERS_LEN] = [
|
||||
("after-parse", Duration::ZERO),
|
||||
("sort", Duration::ZERO),
|
||||
("count-ids", Duration::ZERO),
|
||||
];
|
||||
#[unsafe(no_mangle)]
|
||||
pub static TIMERS_LEN: usize = 3;
|
||||
|
||||
pub type RangeU = u128;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "Rust" fn challenge_t_usize(buf: &[u8], t: &Instant) -> usize {
|
||||
let s = unsafe { str::from_utf8_unchecked(buf) };
|
||||
let mut lines = s.lines();
|
||||
|
||||
let mut count = 0;
|
||||
|
||||
let mut ranges: Vec<(RangeU, RangeU)> = Vec::new();
|
||||
|
||||
for range in &mut lines {
|
||||
if range.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
let (l, r) = range.split_once('-').unwrap();
|
||||
let (l, r) = (l.parse().unwrap(), r.parse().unwrap());
|
||||
|
||||
ranges.push((l, r));
|
||||
}
|
||||
|
||||
unsafe { TIMERS[0].1 = t.elapsed() };
|
||||
|
||||
ranges.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
|
||||
unsafe { TIMERS[1].1 = t.elapsed() };
|
||||
|
||||
for id in lines {
|
||||
let id: RangeU = id.parse().unwrap();
|
||||
|
||||
if ranges.iter().any(|&(l, r)| (l..=r).contains(&id)) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { TIMERS[2].1 = t.elapsed() };
|
||||
|
||||
count
|
||||
}
|
||||
40
2025/05/p2-hu.rs
Normal file
40
2025/05/p2-hu.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
pub type RangeU = usize;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "Rust" fn challenge_usize(buf: &[u8]) -> usize {
|
||||
let s = unsafe { str::from_utf8_unchecked(buf) };
|
||||
let mut lines = s.lines();
|
||||
|
||||
let mut count = 0;
|
||||
|
||||
let mut ranges: Vec<(RangeU, RangeU)> = Vec::new();
|
||||
|
||||
for range in &mut lines {
|
||||
if range.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
let (l, r) = range.split_once('-').unwrap();
|
||||
let (l, r) = (l.parse().unwrap(), r.parse().unwrap());
|
||||
|
||||
// overlapping here means overlapping or adyacent
|
||||
count += r - l + 1;
|
||||
let overlapping: Option<&mut (RangeU, RangeU)> = None;
|
||||
for (r_l, r_r) in ranges.iter_mut() {
|
||||
if l <= *r_r && r >= *r_r {
|
||||
*r_r = r;
|
||||
//
|
||||
}
|
||||
// (|(l, r)| (l..=r).contains(&fresh))
|
||||
}
|
||||
for fresh in l..=r {
|
||||
println!("{fresh:?}");
|
||||
if ranges.iter().any(|&(l, r)| (l..=r).contains(&fresh)) {
|
||||
count -= 1;
|
||||
}
|
||||
}
|
||||
ranges.push((l, r));
|
||||
}
|
||||
|
||||
count
|
||||
}
|
||||
35
2025/05/p2.rs
Normal file
35
2025/05/p2.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
pub type RangeU = usize;
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "Rust" fn challenge_usize(buf: &[u8]) -> usize {
|
||||
let s = unsafe { str::from_utf8_unchecked(buf) };
|
||||
let mut lines = s.lines();
|
||||
|
||||
let mut ranges: Vec<(RangeU, RangeU)> = Vec::new();
|
||||
|
||||
for range in &mut lines {
|
||||
if range.is_empty() {
|
||||
break;
|
||||
}
|
||||
|
||||
let (l, r) = range.split_once('-').unwrap();
|
||||
let (l, r) = (l.parse().unwrap(), r.parse().unwrap());
|
||||
|
||||
ranges.push((l, r));
|
||||
}
|
||||
|
||||
ranges.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
ranges
|
||||
.into_iter()
|
||||
.fold((0, 0), |(count, rightmost), (l, r)| {
|
||||
// dbg!((rightmost, r));
|
||||
if rightmost >= r {
|
||||
(count, rightmost)
|
||||
} else if rightmost >= l {
|
||||
let overlap = rightmost - l + 1;
|
||||
(count + r - l - overlap + 1, rightmost.max(r))
|
||||
} else {
|
||||
(count + r - l + 1, r)
|
||||
}
|
||||
}).0
|
||||
}
|
||||
@@ -7,7 +7,7 @@ use std::{
|
||||
io::{self, Read},
|
||||
path::{Path, PathBuf},
|
||||
process::{Command, Stdio},
|
||||
time::{self, Instant},
|
||||
time::{self, Duration, Instant},
|
||||
};
|
||||
|
||||
pub mod dl {
|
||||
@@ -268,42 +268,68 @@ pub type ChallengeFn = unsafe extern "Rust" fn(&[u8]) -> isize;
|
||||
fn main() -> io::Result<()> {
|
||||
let rustc = env::var("RUSTC_PATH").ok();
|
||||
|
||||
let Ok([day, input]) = std::env::args().skip(1).next_chunk() else {
|
||||
eprintln!("\x1b[1;31mUsage: $0 <PATH.RS> <FILEPATH|->");
|
||||
let args = std::env::args().skip(1).collect::<Vec<_>>();
|
||||
if args.len() < 2 {
|
||||
eprintln!("\x1b[1;31mUsage: $0 <PATHS.RS> <FILEPATH|->");
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let [days @ .., input] = &args[..] else {
|
||||
unreachable!("already checked arg count before");
|
||||
};
|
||||
|
||||
let (noop_overhead_cold, noop_overhead_hot) = measure_noop_overhead();
|
||||
info!(
|
||||
"noop fn takes {:#?} hot and {:#?} cold",
|
||||
noop_overhead_hot, noop_overhead_cold
|
||||
);
|
||||
println!("\x1b[33m prog: buferring input...\x1b[0m");
|
||||
let input = buffer_input(input)?;
|
||||
|
||||
if days.len() == 1 {
|
||||
println!();
|
||||
run_input(&days[0], &input, rustc.as_deref())
|
||||
} else {
|
||||
for day in days {
|
||||
println!();
|
||||
println!("\x1b[1;3;4;41m{day}\x1b[0m:");
|
||||
run_input(day, &input, rustc.as_deref())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn run_input(day: &str, input: &[u8], rustc: Option<&str>) -> io::Result<()> {
|
||||
let rs_path = PathBuf::from(&day);
|
||||
assert_eq!(rs_path.extension(), Some(OsStr::new("rs")));
|
||||
let so_path = rs_path.with_extension("so");
|
||||
|
||||
compile(&rs_path, &so_path, rustc.as_deref())?;
|
||||
println!("\x1b[33mBuferring input...\x1b[0m");
|
||||
let input = buffer_input(&input)?;
|
||||
compile(&rs_path, &so_path, rustc)?;
|
||||
|
||||
let challenge = dl::open(so_path).expect("Couldn't load dyn library");
|
||||
let challenge_main = loader::load_fn_from(&challenge).expect(concat!(
|
||||
let challenge_main = loader::load_fn_from(&challenge).expect(
|
||||
"Didn't find any appropiate symbol in the compiled .so file. Make sure there is one.",
|
||||
));
|
||||
);
|
||||
|
||||
let start = Instant::now();
|
||||
let result = unsafe { challenge_main.call(&input, &start) };
|
||||
let result = unsafe { challenge_main.call(input, &start) };
|
||||
|
||||
let total_time = start.elapsed();
|
||||
println!(
|
||||
"done in {:#?} and yielded result {:?}",
|
||||
start.elapsed(),
|
||||
result
|
||||
"\x1b[32mdone\x1b[0m in \x1b[35m{total_time:#?}\x1b[0m and yielded result \x1b[36m{result:?}\x1b[0m",
|
||||
);
|
||||
if let Some(timers) = loader::load_timers_from(&challenge) {
|
||||
println!("with timers:");
|
||||
for (name, timer) in timers {
|
||||
println!(" '{name}': {timer:#?}");
|
||||
let mut prev_t = Duration::ZERO;
|
||||
for (name, cum_timer) in timers {
|
||||
let timer = *cum_timer - prev_t;
|
||||
println!(
|
||||
" '\x1b[36m{name}\x1b[0m': \x1b[35m{timer:#?}\x1b[0m (\x1b[1;33m{:.2}%\x1b[0m) \x1b[35m{cum_timer:#?}\x1b[0m (\x1b[1;33m{:.2}%\x1b[0m)",
|
||||
(timer.as_nanos() as f64 / total_time.as_nanos() as f64) * 100.0,
|
||||
(cum_timer.as_nanos() as f64 / total_time.as_nanos() as f64) * 100.0
|
||||
);
|
||||
|
||||
prev_t = *cum_timer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,14 +360,14 @@ fn compile(rs: &Path, so: &Path, rustc: Option<&str>) -> io::Result<()> {
|
||||
|
||||
// No need to recompile
|
||||
if so_metadata.modified()? > rs_metadata.modified()? {
|
||||
println!("\x1b[32mChallenge already compiled\x1b[0m");
|
||||
println!("\x1b[32m ok: challenge already compiled\x1b[0m");
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recompile
|
||||
println!("\x1b[33mCompiling {rs:#?}...\x1b[0m");
|
||||
println!("\x1b[33m prog: compiling {rs:#?}...\x1b[0m");
|
||||
let exit = Command::new(rustc.unwrap_or("rustc"))
|
||||
.args([
|
||||
"--crate-type=cdylib",
|
||||
|
||||
Reference in New Issue
Block a user