Skip to main content

reifydb_column/compute/
mod.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4//! Compute kernels that operate on encoded columns. Compare, take, slice, filter, sum, search-sorted, min/max -
5//! the primitives the engine VM dispatches to when it executes the per-instruction work of a query. Kernels
6//! prefer to run directly on the encoded bytes (canonical layout, dictionary indices, run-length runs) and only
7//! decode when they cannot.
8//!
9//! Adding a new kernel here is the right place to make a new operator vectorise; reaching for a per-row
10//! interpreter loop in the VM bypasses the work that lives in this module.
11
12pub mod canonical;
13
14use reifydb_core::value::column::{data::Column, mask::RowMask};
15use reifydb_type::{Result, value::Value};
16
17use crate::encoding;
18
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub enum CompareOp {
21	Eq,
22	Ne,
23	Lt,
24	LtEq,
25	Gt,
26	GtEq,
27}
28
29#[derive(Clone, Debug, PartialEq, Eq)]
30pub enum SearchResult {
31	Found(usize),
32	NotFound(usize),
33}
34
35pub trait Compute: Send + Sync {
36	fn filter(&self, _array: &Column, _mask: &RowMask) -> Option<Result<Column>> {
37		None
38	}
39
40	fn take(&self, _array: &Column, _indices: &Column) -> Option<Result<Column>> {
41		None
42	}
43
44	fn slice(&self, _array: &Column, _start: usize, _end: usize) -> Option<Result<Column>> {
45		None
46	}
47
48	fn compare(&self, _array: &Column, _rhs: &Value, _op: CompareOp) -> Option<Result<Column>> {
49		None
50	}
51
52	fn search_sorted(&self, _array: &Column, _needle: &Value) -> Option<Result<SearchResult>> {
53		None
54	}
55
56	fn min_max(&self, _array: &Column) -> Option<Result<(Value, Value)>> {
57		None
58	}
59
60	fn sum(&self, _array: &Column) -> Option<Result<Value>> {
61		None
62	}
63}
64
65pub struct DefaultCompute;
66
67impl Compute for DefaultCompute {}
68
69pub fn filter(array: &Column, mask: &RowMask) -> Result<Column> {
70	if let Some(result) = specialized(array, |c| c.filter(array, mask)) {
71		return result;
72	}
73	let canon = array.to_canonical()?;
74	Ok(Column::from_canonical(canonical::filter::filter(&canon, mask)?))
75}
76
77pub fn take(array: &Column, indices: &Column) -> Result<Column> {
78	if let Some(result) = specialized(array, |c| c.take(array, indices)) {
79		return result;
80	}
81	let canon = array.to_canonical()?;
82	let idx = indices.to_canonical()?;
83	Ok(Column::from_canonical(canonical::take::take(&canon, &idx)?))
84}
85
86pub fn slice(array: &Column, start: usize, end: usize) -> Result<Column> {
87	if let Some(result) = specialized(array, |c| c.slice(array, start, end)) {
88		return result;
89	}
90	let canon = array.to_canonical()?;
91	Ok(Column::from_canonical(canonical::slice::slice(&canon, start, end)?))
92}
93
94pub fn compare(array: &Column, rhs: &Value, op: CompareOp) -> Result<Column> {
95	if let Some(result) = specialized(array, |c| c.compare(array, rhs, op)) {
96		return result;
97	}
98	let canon = array.to_canonical()?;
99	Ok(Column::from_canonical(canonical::compare::compare(&canon, rhs, op)?))
100}
101
102pub fn search_sorted(array: &Column, needle: &Value) -> Result<SearchResult> {
103	if let Some(result) = specialized(array, |c| c.search_sorted(array, needle)) {
104		return result;
105	}
106	let canon = array.to_canonical()?;
107	canonical::search_sorted::search_sorted(&canon, needle)
108}
109
110pub fn min_max(array: &Column) -> Result<(Value, Value)> {
111	if let Some(result) = specialized(array, |c| c.min_max(array)) {
112		return result;
113	}
114	let canon = array.to_canonical()?;
115	canonical::min_max::min_max(&canon)
116}
117
118pub fn sum(array: &Column) -> Result<Value> {
119	if let Some(result) = specialized(array, |c| c.sum(array)) {
120		return result;
121	}
122	let canon = array.to_canonical()?;
123	canonical::sum::sum(&canon)
124}
125
126fn specialized<T>(array: &Column, hook: impl FnOnce(&dyn Compute) -> Option<Result<T>>) -> Option<Result<T>> {
127	let registry = encoding::global();
128	let encoding = registry.get(array.encoding())?;
129	hook(encoding.compute())
130}