1use std::{
6 any::Any,
7 ops::Deref,
8 sync::{
9 Arc,
10 atomic::{AtomicBool, Ordering},
11 },
12};
13
14use crate::{
15 common::HashMap,
16 free_join::{get_column_index_from_tableinfo, invoke_batch, invoke_batch_assign},
17 numeric_id::{DenseIdMap, NumericId},
18};
19use egglog_concurrency::NotificationList;
20use smallvec::SmallVec;
21
22use crate::{
23 BaseValues, ContainerValues, ExternalFunctionId, Offset, WrappedTable,
24 common::Value,
25 free_join::{CounterId, Counters, ExternalFunctions, TableId, TableInfo, Variable},
26 offsets::Subset,
27 pool::{Clear, Pooled, with_pool_set},
28 row_buffer::TaggedRowBuffer,
29 table_spec::{ColumnId, Constraint, MutationBuffer},
30};
31
32use self::mask::{Mask, MaskIter, ValueSource};
33
34#[macro_use]
35pub(crate) mod mask;
36
37#[cfg(test)]
38mod tests;
39
40#[derive(Copy, Clone, Debug)]
44pub enum QueryEntry {
45 Var(Variable),
46 Const(Value),
47}
48
49impl From<Variable> for QueryEntry {
50 fn from(var: Variable) -> Self {
51 QueryEntry::Var(var)
52 }
53}
54
55impl From<Value> for QueryEntry {
56 fn from(val: Value) -> Self {
57 QueryEntry::Const(val)
58 }
59}
60
61#[derive(Debug, Clone, Copy)]
63pub enum WriteVal {
64 QueryEntry(QueryEntry),
66 IncCounter(CounterId),
68 CurrentVal(usize),
70}
71
72impl<T> From<T> for WriteVal
73where
74 T: Into<QueryEntry>,
75{
76 fn from(val: T) -> Self {
77 WriteVal::QueryEntry(val.into())
78 }
79}
80
81impl From<CounterId> for WriteVal {
82 fn from(ctr: CounterId) -> Self {
83 WriteVal::IncCounter(ctr)
84 }
85}
86
87#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
89pub enum MergeVal {
90 Counter(CounterId),
92 Constant(Value),
94}
95
96impl From<CounterId> for MergeVal {
97 fn from(ctr: CounterId) -> Self {
98 MergeVal::Counter(ctr)
99 }
100}
101
102impl From<Value> for MergeVal {
103 fn from(val: Value) -> Self {
104 MergeVal::Constant(val)
105 }
106}
107
108pub(crate) struct Bindings {
113 matches: usize,
114 max_batch_size: usize,
118 data: Pooled<Vec<Value>>,
119 var_offsets: DenseIdMap<Variable, usize>,
121}
122
123impl std::ops::Index<Variable> for Bindings {
124 type Output = [Value];
125 fn index(&self, var: Variable) -> &[Value] {
126 self.get(var).unwrap()
127 }
128}
129
130impl std::fmt::Debug for Bindings {
131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132 let mut table = f.debug_map();
133 for (var, start) in self.var_offsets.iter() {
134 table.entry(&var, &&self.data[*start..*start + self.matches]);
135 }
136 table.finish()
137 }
138}
139
140impl Bindings {
141 pub(crate) fn new(max_batch_size: usize) -> Self {
142 Bindings {
143 matches: 0,
144 max_batch_size,
145 data: Default::default(),
146 var_offsets: DenseIdMap::new(),
147 }
148 }
149 fn assert_invariant(&self) {
150 #[cfg(debug_assertions)]
151 {
152 assert!(self.matches <= self.max_batch_size);
153 for (var, start) in self.var_offsets.iter() {
154 assert!(
155 start + self.matches <= self.data.len(),
156 "Variable {:?} starts at {}, but data only has {} elements",
157 var,
158 start,
159 self.data.len()
160 );
161 }
162 }
163 }
164
165 pub(crate) fn clear(&mut self) {
166 self.matches = 0;
167 self.var_offsets.clear();
168 self.data.clear();
169 self.assert_invariant();
170 }
171
172 fn get(&self, var: Variable) -> Option<&[Value]> {
173 let start = self.var_offsets.get(var)?;
174 Some(&self.data[*start..*start + self.matches])
175 }
176
177 fn add_mapping(&mut self, var: Variable, vals: &[Value]) {
178 let start = self.data.len();
179 self.data.extend_from_slice(vals);
180 debug_assert!(vals.len() <= self.max_batch_size);
184 if vals.len() < self.max_batch_size {
185 let target_len = self.data.len() + self.max_batch_size - vals.len();
186 self.data.resize(target_len, Value::stale());
187 }
188 self.var_offsets.insert(var, start);
189 }
190
191 pub(crate) fn insert(&mut self, var: Variable, vals: &[Value]) {
192 if self.var_offsets.n_ids() == 0 {
193 self.matches = vals.len();
194 } else {
195 assert_eq!(self.matches, vals.len());
196 }
197 self.add_mapping(var, vals);
198 self.assert_invariant();
199 }
200
201 pub(crate) unsafe fn push(
211 &mut self,
212 map: &DenseIdMap<Variable, Value>,
213 used_vars: &[Variable],
214 ) {
215 if self.matches != 0 {
216 assert!(self.matches < self.max_batch_size);
217 #[cfg(debug_assertions)]
218 {
219 for var in used_vars {
220 assert!(
221 self.var_offsets.get(*var).is_some(),
222 "Variable {:?} not found in bindings {:?}",
223 var,
224 self.var_offsets
225 );
226 }
227 }
228 for var in used_vars {
229 let var = var.index();
230 unsafe {
234 let start = self.var_offsets.raw().get_unchecked(var).unwrap_unchecked();
235 *self.data.get_unchecked_mut(start + self.matches) =
236 map.raw().get_unchecked(var).unwrap_unchecked();
237 }
238 }
239 } else {
240 for (var, val) in map.iter() {
241 self.add_mapping(var, &[*val]);
242 }
243 }
244
245 self.matches += 1;
246 self.assert_invariant();
247 }
248
249 pub(crate) fn take(&mut self, var: Variable) -> Option<ExtractedBinding> {
255 let mut vals: Pooled<Vec<Value>> = with_pool_set(|ps| ps.get());
256 vals.extend_from_slice(self.get(var)?);
257 let start = self.var_offsets.take(var)?;
258 Some(ExtractedBinding {
259 var,
260 offset: start,
261 vals,
262 })
263 }
264
265 pub(crate) fn replace(&mut self, bdg: ExtractedBinding) {
272 let ExtractedBinding {
274 var,
275 offset,
276 mut vals,
277 } = bdg;
278 assert_eq!(vals.len(), self.matches);
279 self.data
280 .splice(offset..offset + self.matches, vals.drain(..));
281 self.var_offsets.insert(var, offset);
282 }
283}
284
285pub(crate) struct ExtractedBinding {
290 var: Variable,
291 offset: usize,
292 pub(crate) vals: Pooled<Vec<Value>>,
293}
294
295#[derive(Default)]
296pub(crate) struct PredictedVals {
297 #[allow(clippy::type_complexity)]
298 data: HashMap<(TableId, SmallVec<[Value; 3]>), Pooled<Vec<Value>>>,
299}
300
301impl Clear for PredictedVals {
302 fn reuse(&self) -> bool {
303 self.data.capacity() > 0
304 }
305 fn clear(&mut self) {
306 self.data.clear()
307 }
308 fn bytes(&self) -> usize {
309 self.data.capacity()
310 * (std::mem::size_of::<(TableId, SmallVec<[Value; 3]>)>()
311 + std::mem::size_of::<Pooled<Vec<Value>>>())
312 }
313}
314
315impl PredictedVals {
316 pub(crate) fn get_val(
317 &mut self,
318 table: TableId,
319 key: &[Value],
320 default: impl FnOnce() -> Pooled<Vec<Value>>,
321 ) -> impl Deref<Target = Pooled<Vec<Value>>> + '_ {
322 self.data
323 .entry((table, SmallVec::from_slice(key)))
324 .or_insert_with(default)
325 }
326}
327
328#[derive(Copy, Clone)]
329pub(crate) struct DbView<'a> {
330 pub(crate) external_context: ExternalContext<'a>,
331 pub(crate) table_info: &'a DenseIdMap<TableId, TableInfo>,
332 pub(crate) counters: &'a Counters,
333 pub(crate) external_funcs: &'a ExternalFunctions,
334 pub(crate) bases: &'a BaseValues,
335 pub(crate) containers: &'a ContainerValues,
336 pub(crate) notification_list: &'a NotificationList<TableId>,
337}
338
339pub type ExternalContext<'a> = Option<&'a (dyn Any + Send + Sync)>;
348
349pub struct ExecutionState<'a> {
375 pub(crate) predicted: PredictedVals,
376 pub(crate) db: DbView<'a>,
377 buffers: MutationBuffers<'a>,
378 pub(crate) changed: bool,
380 stop_match: Arc<AtomicBool>,
383}
384
385struct MutationBuffers<'a> {
388 notify_list: &'a NotificationList<TableId>,
389 buffers: DenseIdMap<TableId, Box<dyn MutationBuffer>>,
390}
391
392impl Clone for MutationBuffers<'_> {
393 fn clone(&self) -> Self {
394 let mut res = MutationBuffers::new(self.notify_list, Default::default());
395 for (id, buf) in self.buffers.iter() {
396 res.buffers.insert(id, buf.fresh_handle());
397 }
398 res
399 }
400}
401
402impl<'a> MutationBuffers<'a> {
403 fn new(
404 notify_list: &'a NotificationList<TableId>,
405 buffers: DenseIdMap<TableId, Box<dyn MutationBuffer>>,
406 ) -> MutationBuffers<'a> {
407 MutationBuffers {
408 notify_list,
409 buffers,
410 }
411 }
412 fn lazy_init(&mut self, table_id: TableId, f: impl FnOnce() -> Box<dyn MutationBuffer>) {
413 self.buffers.get_or_insert(table_id, f);
414 }
415 fn stage_insert(&mut self, table_id: TableId, row: &[Value]) {
416 self.buffers[table_id].stage_insert(row);
417 self.notify_list.notify(table_id);
418 }
419
420 fn stage_remove(&mut self, table_id: TableId, key: &[Value]) {
421 self.buffers[table_id].stage_remove(key);
422 self.notify_list.notify(table_id);
423 }
424}
425
426impl Clone for ExecutionState<'_> {
427 fn clone(&self) -> Self {
428 ExecutionState {
429 predicted: Default::default(),
430 db: self.db,
431 buffers: self.buffers.clone(),
432 changed: false,
433 stop_match: Arc::clone(&self.stop_match),
434 }
435 }
436}
437
438impl<'a> ExecutionState<'a> {
439 pub(crate) fn new(
440 db: DbView<'a>,
441 buffers: DenseIdMap<TableId, Box<dyn MutationBuffer>>,
442 ) -> Self {
443 ExecutionState {
444 predicted: Default::default(),
445 db,
446 buffers: MutationBuffers::new(db.notification_list, buffers),
447 changed: false,
448 stop_match: Arc::new(AtomicBool::new(false)),
449 }
450 }
451
452 pub fn stage_insert(&mut self, table: TableId, row: &[Value]) {
456 self.buffers
457 .lazy_init(table, || self.db.table_info[table].table.new_buffer());
458 self.buffers.stage_insert(table, row);
459 self.changed = true;
460 }
461
462 pub fn stage_remove(&mut self, table: TableId, key: &[Value]) {
466 self.buffers
467 .lazy_init(table, || self.db.table_info[table].table.new_buffer());
468 self.buffers.stage_remove(table, key);
469 self.changed = true;
470 }
471
472 pub fn call_external_func(
474 &mut self,
475 func: ExternalFunctionId,
476 args: &[Value],
477 ) -> Option<Value> {
478 self.db.external_funcs[func].invoke(self, args)
479 }
480
481 pub fn external_context(&self) -> ExternalContext<'a> {
484 self.db.external_context
485 }
486
487 pub fn inc_counter(&self, ctr: CounterId) -> usize {
488 self.db.counters.inc(ctr)
489 }
490
491 pub fn read_counter(&self, ctr: CounterId) -> usize {
492 self.db.counters.read(ctr)
493 }
494
495 pub fn table_ids(&self) -> impl Iterator<Item = TableId> + '_ {
497 self.db.table_info.iter().map(|(id, _)| id)
498 }
499
500 pub fn get_table(&self, table: TableId) -> &'a WrappedTable {
503 &self.db.table_info[table].table
504 }
505
506 pub fn for_each_matching_col(
509 &self,
510 table: TableId,
511 col: ColumnId,
512 value: Value,
513 mut f: impl FnMut(&[Value]),
514 ) {
515 let table_info = &self.db.table_info[table];
516 let constraint = Constraint::EqConst { col, val: value };
517
518 let cacheable = !*table_info
523 .spec
524 .uncacheable_columns
525 .get(col)
526 .unwrap_or(&false);
527 let (subset, slow) = if let Some(subset) = table_info.table.fast_subset(&constraint) {
528 (subset, Vec::new())
529 } else if cacheable {
530 let index = get_column_index_from_tableinfo(table_info, col);
531 let subset = match index.get().unwrap().get_subset(&value) {
532 Some(subset) => with_pool_set(|ps| subset.to_owned(&ps.get_pool())),
533 None => Subset::empty(),
535 };
536 (subset, Vec::new())
537 } else {
538 (table_info.table.all(), vec![constraint])
539 };
540
541 let imp = &table_info.table;
542 let cols: SmallVec<[_; 8]> = (0..imp.spec().arity()).map(ColumnId::from_usize).collect();
543 let mut cur = Offset::new(0);
544 let mut buf = TaggedRowBuffer::new_inline(imp.spec().arity());
545
546 macro_rules! drain_buf {
547 ($buf:expr) => {
548 for (_, row) in $buf.iter() {
549 f(row);
550 }
551 $buf.clear();
552 };
553 }
554
555 while let Some(next) = imp.scan_project(subset.as_ref(), &cols, cur, 1024, &slow, &mut buf)
556 {
557 drain_buf!(buf);
558 cur = next;
559 }
560 drain_buf!(buf);
561 }
562
563 pub fn table_name(&self, table: TableId) -> Option<&'a str> {
565 self.db.table_info[table].name()
566 }
567
568 pub fn base_values(&self) -> &'a BaseValues {
569 self.db.bases
570 }
571
572 pub fn container_values(&self) -> &'a ContainerValues {
573 self.db.containers
574 }
575
576 pub fn predict_val(
586 &mut self,
587 table: TableId,
588 key: &[Value],
589 vals: impl ExactSizeIterator<Item = MergeVal>,
590 ) -> Pooled<Vec<Value>> {
591 if let Some(row) = self.db.table_info[table].table.get_row(key) {
592 return row.vals;
593 }
594 Pooled::cloned(
595 self.predicted
596 .get_val(table, key, || {
597 Self::construct_new_row(
598 &self.db,
599 &mut self.buffers,
600 &mut self.changed,
601 table,
602 key,
603 vals,
604 )
605 })
606 .deref(),
607 )
608 }
609
610 fn construct_new_row(
611 db: &DbView,
612 buffers: &mut MutationBuffers,
613 changed: &mut bool,
614 table: TableId,
615 key: &[Value],
616 vals: impl ExactSizeIterator<Item = MergeVal>,
617 ) -> Pooled<Vec<Value>> {
618 with_pool_set(|ps| {
619 let mut new = ps.get::<Vec<Value>>();
620 new.reserve(key.len() + vals.len());
621 new.extend_from_slice(key);
622 for val in vals {
623 new.push(match val {
624 MergeVal::Counter(ctr) => Value::from_usize(db.counters.inc(ctr)),
625 MergeVal::Constant(c) => c,
626 })
627 }
628 buffers.lazy_init(table, || db.table_info[table].table.new_buffer());
629 buffers.stage_insert(table, &new);
630 *changed = true;
631 new
632 })
633 }
634
635 pub fn predict_col(
638 &mut self,
639 table: TableId,
640 key: &[Value],
641 vals: impl ExactSizeIterator<Item = MergeVal>,
642 col: ColumnId,
643 ) -> Value {
644 if let Some(val) = self.db.table_info[table].table.get_row_column(key, col) {
645 return val;
646 }
647 self.predicted.get_val(table, key, || {
648 Self::construct_new_row(
649 &self.db,
650 &mut self.buffers,
651 &mut self.changed,
652 table,
653 key,
654 vals,
655 )
656 })[col.index()]
657 }
658
659 pub fn trigger_early_stop(&self) {
664 self.stop_match.store(true, Ordering::Release);
665 }
666
667 pub fn should_stop(&self) -> bool {
671 self.stop_match.load(Ordering::Acquire)
672 }
673}
674
675impl ExecutionState<'_> {
676 pub(crate) fn run_instrs(&mut self, instrs: &[Instr], bindings: &mut Bindings) -> usize {
678 if bindings.var_offsets.next_id().rep() == 0 {
679 bindings.matches = 1;
681 }
682
683 let mut mask = with_pool_set(|ps| Mask::new(0..bindings.matches, ps));
685 for instr in instrs {
686 if mask.is_empty() {
687 return 0;
688 }
689 self.run_instr(&mut mask, instr, bindings);
690 }
691 mask.count_ones()
692 }
693 fn run_instr(&mut self, mask: &mut Mask, inst: &Instr, bindings: &mut Bindings) {
694 fn assert_impl(
695 bindings: &mut Bindings,
696 mask: &mut Mask,
697 l: &QueryEntry,
698 r: &QueryEntry,
699 op: impl Fn(Value, Value) -> bool,
700 ) {
701 match (l, r) {
702 (QueryEntry::Var(v1), QueryEntry::Var(v2)) => {
703 mask.iter(&bindings[*v1])
704 .zip(&bindings[*v2])
705 .retain(|(v1, v2)| op(*v1, *v2));
706 }
707 (QueryEntry::Var(v), QueryEntry::Const(c))
708 | (QueryEntry::Const(c), QueryEntry::Var(v)) => {
709 mask.iter(&bindings[*v]).retain(|v| op(*v, *c));
710 }
711 (QueryEntry::Const(c1), QueryEntry::Const(c2)) => {
712 if !op(*c1, *c2) {
713 mask.clear();
714 }
715 }
716 }
717 }
718
719 match inst {
720 Instr::LookupOrInsertDefault {
721 table: table_id,
722 args,
723 default,
724 dst_col,
725 dst_var,
726 } => {
727 let pool = with_pool_set(|ps| ps.get_pool::<Vec<Value>>().clone());
728 self.buffers.lazy_init(*table_id, || {
729 self.db.table_info[*table_id].table.new_buffer()
730 });
731 let table = &self.db.table_info[*table_id].table;
732 let mut mask_copy = mask.clone();
735 table.lookup_row_vectorized(&mut mask_copy, bindings, args, *dst_col, *dst_var);
736 mask_copy.symmetric_difference(mask);
737 if mask_copy.is_empty() {
738 return;
739 }
740 let mut out = bindings.take(*dst_var).unwrap();
741 for_each_binding_with_mask!(mask_copy, args.as_slice(), bindings, |iter| {
742 iter.assign_vec(&mut out.vals, |offset, key| {
743 let prediction_key = (
752 *table_id,
753 SmallVec::<[Value; 3]>::from_slice(key.as_slice()),
754 );
755 let buffers = &mut self.buffers;
756 let ctrs = &self.db.counters;
759 let bindings = &bindings;
760 let pool = pool.clone();
761 let row =
762 self.predicted
763 .data
764 .entry(prediction_key)
765 .or_insert_with(move || {
766 let mut row = pool.get();
767 row.extend_from_slice(key.as_slice());
768 row.reserve(default.len());
770 for val in default {
771 let val = match val {
772 WriteVal::QueryEntry(QueryEntry::Const(c)) => *c,
773 WriteVal::QueryEntry(QueryEntry::Var(v)) => {
774 bindings[*v][offset]
775 }
776 WriteVal::IncCounter(ctr) => {
777 Value::from_usize(ctrs.inc(*ctr))
778 }
779 WriteVal::CurrentVal(ix) => row[*ix],
780 };
781 row.push(val)
782 }
783 buffers.stage_insert(*table_id, &row);
785 row
786 });
787 row[dst_col.index()]
788 });
789 });
790 bindings.replace(out);
791 }
792 Instr::LookupWithDefault {
793 table,
794 args,
795 dst_col,
796 dst_var,
797 default,
798 } => {
799 let table = &self.db.table_info[*table].table;
800 table.lookup_with_default_vectorized(
801 mask, bindings, args, *dst_col, *default, *dst_var,
802 );
803 }
804 Instr::Lookup {
805 table,
806 args,
807 dst_col,
808 dst_var,
809 } => {
810 let table = &self.db.table_info[*table].table;
811 table.lookup_row_vectorized(mask, bindings, args, *dst_col, *dst_var);
812 }
813
814 Instr::LookupWithFallback {
815 table: table_id,
816 table_key,
817 func,
818 func_args,
819 dst_col,
820 dst_var,
821 } => {
822 let table = &self.db.table_info[*table_id].table;
823 let mut lookup_result = mask.clone();
824 table.lookup_row_vectorized(
825 &mut lookup_result,
826 bindings,
827 table_key,
828 *dst_col,
829 *dst_var,
830 );
831 let mut to_call_func = lookup_result.clone();
832 to_call_func.symmetric_difference(mask);
833 if to_call_func.is_empty() {
834 return;
835 }
836
837 invoke_batch_assign(
839 self.db.external_funcs[*func].as_ref(),
840 self,
841 &mut to_call_func,
842 bindings,
843 func_args,
844 *dst_var,
845 );
846 lookup_result.union(&to_call_func);
849 *mask = lookup_result;
850 }
851 Instr::Insert { table, vals } => {
852 for_each_binding_with_mask!(mask, vals.as_slice(), bindings, |iter| {
853 iter.for_each(|vals| {
854 self.stage_insert(*table, vals.as_slice());
855 })
856 });
857 }
858 Instr::InsertIfEq { table, l, r, vals } => match (l, r) {
859 (QueryEntry::Var(v1), QueryEntry::Var(v2)) => {
860 for_each_binding_with_mask!(mask, vals.as_slice(), bindings, |iter| {
861 iter.zip(&bindings[*v1])
862 .zip(&bindings[*v2])
863 .for_each(|((vals, v1), v2)| {
864 if v1 == v2 {
865 self.stage_insert(*table, &vals);
866 }
867 })
868 })
869 }
870 (QueryEntry::Var(v), QueryEntry::Const(c))
871 | (QueryEntry::Const(c), QueryEntry::Var(v)) => {
872 for_each_binding_with_mask!(mask, vals.as_slice(), bindings, |iter| {
873 iter.zip(&bindings[*v]).for_each(|(vals, cond)| {
874 if cond == c {
875 self.stage_insert(*table, &vals);
876 }
877 })
878 })
879 }
880 (QueryEntry::Const(c1), QueryEntry::Const(c2)) => {
881 if c1 == c2 {
882 for_each_binding_with_mask!(mask, vals.as_slice(), bindings, |iter| iter
883 .for_each(|vals| {
884 self.stage_insert(*table, &vals);
885 }))
886 }
887 }
888 },
889 Instr::Remove { table, args } => {
890 for_each_binding_with_mask!(mask, args.as_slice(), bindings, |iter| {
891 iter.for_each(|args| {
892 self.stage_remove(*table, args.as_slice());
893 })
894 });
895 }
896 Instr::External { func, args, dst } => {
897 invoke_batch(
898 self.db.external_funcs[*func].as_ref(),
899 self,
900 mask,
901 bindings,
902 args,
903 *dst,
904 );
905 }
906 Instr::ExternalWithFallback {
907 f1,
908 args1,
909 f2,
910 args2,
911 dst,
912 } => {
913 let mut f1_result = mask.clone();
914 invoke_batch(
915 self.db.external_funcs[*f1].as_ref(),
916 self,
917 &mut f1_result,
918 bindings,
919 args1,
920 *dst,
921 );
922 let mut to_call_f2 = f1_result.clone();
923 to_call_f2.symmetric_difference(mask);
924 if to_call_f2.is_empty() {
925 return;
926 }
927 invoke_batch_assign(
929 self.db.external_funcs[*f2].as_ref(),
930 self,
931 &mut to_call_f2,
932 bindings,
933 args2,
934 *dst,
935 );
936 f1_result.union(&to_call_f2);
938 *mask = f1_result;
939 }
940 Instr::AssertAnyNe { ops, divider } => {
941 for_each_binding_with_mask!(mask, ops.as_slice(), bindings, |iter| {
942 iter.retain(|vals| {
943 vals[0..*divider]
944 .iter()
945 .zip(&vals[*divider..])
946 .any(|(l, r)| l != r)
947 })
948 })
949 }
950 Instr::AssertEq(l, r) => assert_impl(bindings, mask, l, r, |l, r| l == r),
951 Instr::AssertNe(l, r) => assert_impl(bindings, mask, l, r, |l, r| l != r),
952 Instr::ReadCounter { counter, dst } => {
953 let mut vals = with_pool_set(|ps| ps.get::<Vec<Value>>());
954 let ctr_val = Value::from_usize(self.read_counter(*counter));
955 vals.resize(bindings.matches, ctr_val);
956 bindings.insert(*dst, &vals);
957 }
958 }
959 }
960}
961
962#[derive(Debug, Clone)]
963pub(crate) enum Instr {
964 LookupOrInsertDefault {
967 table: TableId,
968 args: Vec<QueryEntry>,
969 default: Vec<WriteVal>,
970 dst_col: ColumnId,
971 dst_var: Variable,
972 },
973
974 LookupWithDefault {
977 table: TableId,
978 args: Vec<QueryEntry>,
979 dst_col: ColumnId,
980 dst_var: Variable,
981 default: QueryEntry,
982 },
983
984 Lookup {
987 table: TableId,
988 args: Vec<QueryEntry>,
989 dst_col: ColumnId,
990 dst_var: Variable,
991 },
992
993 LookupWithFallback {
998 table: TableId,
999 table_key: Vec<QueryEntry>,
1000 func: ExternalFunctionId,
1001 func_args: Vec<QueryEntry>,
1002 dst_col: ColumnId,
1003 dst_var: Variable,
1004 },
1005
1006 Insert {
1009 table: TableId,
1010 vals: Vec<QueryEntry>,
1011 },
1012
1013 InsertIfEq {
1015 table: TableId,
1016 l: QueryEntry,
1017 r: QueryEntry,
1018 vals: Vec<QueryEntry>,
1019 },
1020
1021 Remove {
1023 table: TableId,
1024 args: Vec<QueryEntry>,
1025 },
1026
1027 External {
1029 func: ExternalFunctionId,
1030 args: Vec<QueryEntry>,
1031 dst: Variable,
1032 },
1033
1034 ExternalWithFallback {
1038 f1: ExternalFunctionId,
1039 args1: Vec<QueryEntry>,
1040 f2: ExternalFunctionId,
1041 args2: Vec<QueryEntry>,
1042 dst: Variable,
1043 },
1044
1045 AssertEq(QueryEntry, QueryEntry),
1047
1048 AssertNe(QueryEntry, QueryEntry),
1050
1051 AssertAnyNe {
1055 ops: Vec<QueryEntry>,
1056 divider: usize,
1057 },
1058
1059 ReadCounter {
1061 counter: CounterId,
1063 dst: Variable,
1065 },
1066}