From 8cf9c2719652d298006d51bc82a32908ab4e5335 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 12 Sep 2018 21:50:15 +0300 Subject: generic salsa algo --- crates/salsa/tests/integration.rs | 153 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 crates/salsa/tests/integration.rs (limited to 'crates/salsa/tests') diff --git a/crates/salsa/tests/integration.rs b/crates/salsa/tests/integration.rs new file mode 100644 index 000000000..7241eca38 --- /dev/null +++ b/crates/salsa/tests/integration.rs @@ -0,0 +1,153 @@ +extern crate salsa; +use std::{ + sync::Arc, + collections::hash_map::{HashMap, DefaultHasher}, + any::Any, + hash::{Hash, Hasher}, +}; + +type State = HashMap; +const GET_TEXT: salsa::QueryTypeId = salsa::QueryTypeId(1); +const GET_FILES: salsa::QueryTypeId = salsa::QueryTypeId(2); +const FILE_NEWLINES: salsa::QueryTypeId = salsa::QueryTypeId(3); +const TOTAL_NEWLINES: salsa::QueryTypeId = salsa::QueryTypeId(4); + +fn mk_ground_query( + state: &State, + params: &(Any + Send + Sync + 'static), + f: fn(&State, &T) -> R, +) -> (Box, salsa::OutputFingerprint) +where + T: 'static, + R: Hash + Send + Sync + 'static, +{ + let params = params.downcast_ref().unwrap(); + let result = f(state, params); + let fingerprint = o_print(&result); + (Box::new(result), fingerprint) +} + +fn get(db: &salsa::Db, query_type: salsa::QueryTypeId, param: T) -> (Arc, Vec) +where + T: Hash + Send + Sync + 'static, + R: Send + Sync + 'static, +{ + let i_print = i_print(¶m); + let param = Box::new(param); + let (res, trace) = db.get(salsa::QueryId(query_type, i_print), param); + (res.downcast().unwrap(), trace) +} + +struct QueryCtx<'a>(&'a salsa::QueryCtx); + +impl<'a> QueryCtx<'a> { + fn get_text(&self, id: u32) -> Arc { + let i_print = i_print(&id); + let text = self.0.get(salsa::QueryId(GET_TEXT, i_print), Arc::new(id)); + text.downcast().unwrap() + } + fn get_files(&self) -> Arc> { + let i_print = i_print(&()); + let files = self.0.get(salsa::QueryId(GET_FILES, i_print), Arc::new(())); + let res = files.downcast().unwrap(); + res + } + fn get_n_lines(&self, id: u32) -> usize { + let i_print = i_print(&id); + let n_lines = self.0.get(salsa::QueryId(FILE_NEWLINES, i_print), Arc::new(id)); + *n_lines.downcast().unwrap() + } +} + +fn mk_query( + query_ctx: &salsa::QueryCtx, + params: &(Any + Send + Sync + 'static), + f: fn(QueryCtx, &T) -> R, +) -> (Box, salsa::OutputFingerprint) +where + T: 'static, + R: Hash + Send + Sync + 'static, +{ + let params: &T = params.downcast_ref().unwrap(); + let query_ctx = QueryCtx(query_ctx); + let result = f(query_ctx, params); + let fingerprint = o_print(&result); + (Box::new(result), fingerprint) +} + +fn mk_queries() -> salsa::QueryConfig { + salsa::QueryConfig::::new() + .with_ground_query(GET_TEXT, |state, id| { + mk_ground_query::(state, id, |state, id| state[id].clone()) + }) + .with_ground_query(GET_FILES, |state, id| { + mk_ground_query::<(), Vec>(state, id, |state, &()| state.keys().cloned().collect()) + }) + .with_query(FILE_NEWLINES, |query_ctx, id| { + mk_query(query_ctx, id, |query_ctx, &id| { + let text = query_ctx.get_text(id); + text.lines().count() + }) + }) + .with_query(TOTAL_NEWLINES, |query_ctx, id| { + mk_query(query_ctx, id, |query_ctx, &()| { + let mut total = 0; + for &id in query_ctx.get_files().iter() { + total += query_ctx.get_n_lines(id) + } + total + }) + }) +} + +#[test] +fn test_number_of_lines() { + let mut state = State::new(); + let db = salsa::Db::new(mk_queries(), state.clone()); + let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ()); + assert_eq!(*newlines, 0); + assert_eq!(trace.len(), 2); + let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ()); + assert_eq!(*newlines, 0); + assert_eq!(trace.len(), 0); + + state.insert(1, "hello\nworld".to_string()); + let db = db.with_ground_data(state.clone()); + let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ()); + assert_eq!(*newlines, 2); + assert_eq!(trace.len(), 4); + + state.insert(2, "spam\neggs".to_string()); + let db = db.with_ground_data(state.clone()); + let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ()); + assert_eq!(*newlines, 4); + assert_eq!(trace.len(), 5); + + for i in 0..10 { + state.insert(i + 10, "spam".to_string()); + } + let db = db.with_ground_data(state.clone()); + let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ()); + assert_eq!(*newlines, 14); + assert_eq!(trace.len(), 24); + + state.insert(15, String::new()); + let db = db.with_ground_data(state.clone()); + let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ()); + assert_eq!(*newlines, 13); + assert_eq!(trace.len(), 15); +} + +fn o_print(x: &T) -> salsa::OutputFingerprint { + let mut hasher = DefaultHasher::new(); + x.hash(&mut hasher); + let hash = hasher.finish(); + salsa::OutputFingerprint(hash) +} + +fn i_print(x: &T) -> salsa::InputFingerprint { + let mut hasher = DefaultHasher::new(); + x.hash(&mut hasher); + let hash = hasher.finish(); + salsa::InputFingerprint(hash) +} -- cgit v1.2.3 From cecc7ad5b20e693cb8d962187bd83b9ac234de97 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 12 Sep 2018 22:11:26 +0300 Subject: be generic over data --- crates/salsa/tests/integration.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'crates/salsa/tests') diff --git a/crates/salsa/tests/integration.rs b/crates/salsa/tests/integration.rs index 7241eca38..2872d3913 100644 --- a/crates/salsa/tests/integration.rs +++ b/crates/salsa/tests/integration.rs @@ -7,6 +7,7 @@ use std::{ }; type State = HashMap; +type Data = Arc; const GET_TEXT: salsa::QueryTypeId = salsa::QueryTypeId(1); const GET_FILES: salsa::QueryTypeId = salsa::QueryTypeId(2); const FILE_NEWLINES: salsa::QueryTypeId = salsa::QueryTypeId(3); @@ -14,9 +15,9 @@ const TOTAL_NEWLINES: salsa::QueryTypeId = salsa::QueryTypeId(4); fn mk_ground_query( state: &State, - params: &(Any + Send + Sync + 'static), + params: &Data, f: fn(&State, &T) -> R, -) -> (Box, salsa::OutputFingerprint) +) -> (Data, salsa::OutputFingerprint) where T: 'static, R: Hash + Send + Sync + 'static, @@ -24,21 +25,21 @@ where let params = params.downcast_ref().unwrap(); let result = f(state, params); let fingerprint = o_print(&result); - (Box::new(result), fingerprint) + (Arc::new(result), fingerprint) } -fn get(db: &salsa::Db, query_type: salsa::QueryTypeId, param: T) -> (Arc, Vec) +fn get(db: &salsa::Db, query_type: salsa::QueryTypeId, param: T) -> (Arc, Vec) where T: Hash + Send + Sync + 'static, R: Send + Sync + 'static, { let i_print = i_print(¶m); - let param = Box::new(param); + let param = Arc::new(param); let (res, trace) = db.get(salsa::QueryId(query_type, i_print), param); (res.downcast().unwrap(), trace) } -struct QueryCtx<'a>(&'a salsa::QueryCtx); +struct QueryCtx<'a>(&'a salsa::QueryCtx); impl<'a> QueryCtx<'a> { fn get_text(&self, id: u32) -> Arc { @@ -60,10 +61,10 @@ impl<'a> QueryCtx<'a> { } fn mk_query( - query_ctx: &salsa::QueryCtx, - params: &(Any + Send + Sync + 'static), + query_ctx: &salsa::QueryCtx, + params: &Data, f: fn(QueryCtx, &T) -> R, -) -> (Box, salsa::OutputFingerprint) +) -> (Data, salsa::OutputFingerprint) where T: 'static, R: Hash + Send + Sync + 'static, @@ -72,11 +73,11 @@ where let query_ctx = QueryCtx(query_ctx); let result = f(query_ctx, params); let fingerprint = o_print(&result); - (Box::new(result), fingerprint) + (Arc::new(result), fingerprint) } -fn mk_queries() -> salsa::QueryConfig { - salsa::QueryConfig::::new() +fn mk_queries() -> salsa::QueryConfig { + salsa::QueryConfig::::new() .with_ground_query(GET_TEXT, |state, id| { mk_ground_query::(state, id, |state, id| state[id].clone()) }) -- cgit v1.2.3 From 60fdfec32759d5e006eae9fe09a87b1a28b19983 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 12 Sep 2018 22:30:48 +0300 Subject: eager invalidation --- crates/salsa/tests/integration.rs | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) (limited to 'crates/salsa/tests') diff --git a/crates/salsa/tests/integration.rs b/crates/salsa/tests/integration.rs index 2872d3913..3cec330e6 100644 --- a/crates/salsa/tests/integration.rs +++ b/crates/salsa/tests/integration.rs @@ -1,5 +1,6 @@ extern crate salsa; use std::{ + iter::once, sync::Arc, collections::hash_map::{HashMap, DefaultHasher}, any::Any, @@ -113,30 +114,45 @@ fn test_number_of_lines() { assert_eq!(trace.len(), 0); state.insert(1, "hello\nworld".to_string()); - let db = db.with_ground_data(state.clone()); + let mut inv = salsa::Invalidations::new(); + inv.invalidate(GET_TEXT, once(i_print(&1u32))); + inv.invalidate(GET_FILES, once(i_print(&()))); + let db = db.with_ground_data(state.clone(), inv); let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ()); assert_eq!(*newlines, 2); assert_eq!(trace.len(), 4); state.insert(2, "spam\neggs".to_string()); - let db = db.with_ground_data(state.clone()); + let mut inv = salsa::Invalidations::new(); + inv.invalidate(GET_TEXT, once(i_print(&2u32))); + inv.invalidate(GET_FILES, once(i_print(&()))); + let db = db.with_ground_data(state.clone(), inv); let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ()); assert_eq!(*newlines, 4); - assert_eq!(trace.len(), 5); + assert_eq!(trace.len(), 4); + let mut invs = vec![]; for i in 0..10 { - state.insert(i + 10, "spam".to_string()); + let id = i + 10; + invs.push(i_print(&id)); + state.insert(id, "spam".to_string()); } - let db = db.with_ground_data(state.clone()); + let mut inv = salsa::Invalidations::new(); + inv.invalidate(GET_TEXT, invs.into_iter()); + inv.invalidate(GET_FILES, once(i_print(&()))); + let db = db.with_ground_data(state.clone(), inv); let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ()); assert_eq!(*newlines, 14); - assert_eq!(trace.len(), 24); + assert_eq!(trace.len(), 22); state.insert(15, String::new()); - let db = db.with_ground_data(state.clone()); + let mut inv = salsa::Invalidations::new(); + inv.invalidate(GET_TEXT, once(i_print(&15u32))); + inv.invalidate(GET_FILES, once(i_print(&()))); + let db = db.with_ground_data(state.clone(), inv); let (newlines, trace) = get::<(), usize>(&db, TOTAL_NEWLINES, ()); assert_eq!(*newlines, 13); - assert_eq!(trace.len(), 15); + assert_eq!(trace.len(), 4); } fn o_print(x: &T) -> salsa::OutputFingerprint { -- cgit v1.2.3 From 8c737255ff876fc61f8dc8a7d33252476a4b4c8d Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 13 Sep 2018 22:58:36 +0300 Subject: use salsa for new module map --- crates/salsa/tests/integration.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'crates/salsa/tests') diff --git a/crates/salsa/tests/integration.rs b/crates/salsa/tests/integration.rs index 3cec330e6..aed9219be 100644 --- a/crates/salsa/tests/integration.rs +++ b/crates/salsa/tests/integration.rs @@ -79,19 +79,19 @@ where fn mk_queries() -> salsa::QueryConfig { salsa::QueryConfig::::new() - .with_ground_query(GET_TEXT, |state, id| { + .with_ground_query(GET_TEXT, Box::new(|state, id| { mk_ground_query::(state, id, |state, id| state[id].clone()) - }) - .with_ground_query(GET_FILES, |state, id| { + })) + .with_ground_query(GET_FILES, Box::new(|state, id| { mk_ground_query::<(), Vec>(state, id, |state, &()| state.keys().cloned().collect()) - }) - .with_query(FILE_NEWLINES, |query_ctx, id| { + })) + .with_query(FILE_NEWLINES, Box::new(|query_ctx, id| { mk_query(query_ctx, id, |query_ctx, &id| { let text = query_ctx.get_text(id); text.lines().count() }) - }) - .with_query(TOTAL_NEWLINES, |query_ctx, id| { + })) + .with_query(TOTAL_NEWLINES, Box::new(|query_ctx, id| { mk_query(query_ctx, id, |query_ctx, &()| { let mut total = 0; for &id in query_ctx.get_files().iter() { @@ -99,7 +99,7 @@ fn mk_queries() -> salsa::QueryConfig { } total }) - }) + })) } #[test] -- cgit v1.2.3